From 8ad711a98d4094571aafb40e9c996d07fc733221 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Mon, 23 Jun 2014 11:32:14 +0530 Subject: [PATCH 01/82] serial: samsung: Remove redundant label probe_err label only returns the error code. This label can be removed and the error code can be returned directly. Signed-off-by: Tushar Behera Reviewed-by: Sachin Kamat Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index c1d3ebdf3b97..bf9301094c41 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1303,7 +1303,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ret = s3c24xx_serial_init_port(ourport, pdev); if (ret < 0) - goto probe_err; + return ret; if (!s3c24xx_uart_drv.state) { ret = uart_register_driver(&s3c24xx_uart_drv); @@ -1335,9 +1335,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to add cpufreq notifier\n"); return 0; - - probe_err: - return ret; } static int s3c24xx_serial_remove(struct platform_device *dev) From 7f6d942a819cd29854903097392b29010cbcf4da Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 26 Jun 2014 15:35:35 +0530 Subject: [PATCH 02/82] serial: amba-pl011: Remove redundant label The label 'out' is only used to return the error code. We can return the error code directly and remove 'out' label. Signed-off-by: Tushar Behera Reviewed-by: Daniel Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 0e26dcbd5ea4..8572f2a57fc8 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1484,7 +1484,7 @@ static int pl011_hwinit(struct uart_port *port) */ retval = clk_prepare_enable(uap->clk); if (retval) - goto out; + return retval; uap->port.uartclk = clk_get_rate(uap->clk); @@ -1507,8 +1507,6 @@ static int pl011_hwinit(struct uart_port *port) plat->init(); } return 0; - out: - return retval; } static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) @@ -2131,32 +2129,24 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) if (amba_ports[i] == NULL) break; - if (i == ARRAY_SIZE(amba_ports)) { - ret = -EBUSY; - goto out; - } + if (i == ARRAY_SIZE(amba_ports)) + return -EBUSY; uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port), GFP_KERNEL); - if (uap == NULL) { - ret = -ENOMEM; - goto out; - } + if (uap == NULL) + return -ENOMEM; i = pl011_probe_dt_alias(i, &dev->dev); base = devm_ioremap(&dev->dev, dev->res.start, resource_size(&dev->res)); - if (!base) { - ret = -ENOMEM; - goto out; - } + if (!base) + return -ENOMEM; uap->clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(uap->clk)) { - ret = PTR_ERR(uap->clk); - goto out; - } + if (IS_ERR(uap->clk)) + return PTR_ERR(uap->clk); uap->vendor = vendor; uap->lcrh_rx = vendor->lcrh_rx; @@ -2198,7 +2188,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uart_unregister_driver(&amba_reg); pl011_dma_remove(uap); } - out: + return ret; } From 44acd26063afd6836e47f76335aaa7779803c8aa Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 26 Jun 2014 15:35:36 +0530 Subject: [PATCH 03/82] serial: amba-pl010: Use devres APIs Migrating to use devres managed APIs devm_kzalloc, devm_ioremap and devm_clk_get. Signed-off-by: Tushar Behera Reviewed-by: Daniel Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl010.c | 48 +++++++++++---------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 971af1e22d0f..2064d31d0c8b 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -46,8 +46,7 @@ #include #include #include - -#include +#include #define UART_NR 8 @@ -688,28 +687,22 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id) if (amba_ports[i] == NULL) break; - if (i == ARRAY_SIZE(amba_ports)) { - ret = -EBUSY; - goto out; - } + if (i == ARRAY_SIZE(amba_ports)) + return -EBUSY; - uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); - if (!uap) { - ret = -ENOMEM; - goto out; - } + uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port), + GFP_KERNEL); + if (!uap) + return -ENOMEM; - base = ioremap(dev->res.start, resource_size(&dev->res)); - if (!base) { - ret = -ENOMEM; - goto free; - } + base = devm_ioremap(&dev->dev, dev->res.start, + resource_size(&dev->res)); + if (!base) + return -ENOMEM; - uap->clk = clk_get(&dev->dev, NULL); - if (IS_ERR(uap->clk)) { - ret = PTR_ERR(uap->clk); - goto unmap; - } + uap->clk = devm_clk_get(&dev->dev, NULL); + if (IS_ERR(uap->clk)) + return PTR_ERR(uap->clk); uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; @@ -727,15 +720,9 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id) amba_set_drvdata(dev, uap); ret = uart_add_one_port(&amba_reg, &uap->port); - if (ret) { + if (ret) amba_ports[i] = NULL; - clk_put(uap->clk); - unmap: - iounmap(base); - free: - kfree(uap); - } - out: + return ret; } @@ -750,9 +737,6 @@ static int pl010_remove(struct amba_device *dev) if (amba_ports[i] == uap) amba_ports[i] = NULL; - iounmap(uap->port.membase); - clk_put(uap->clk); - kfree(uap); return 0; } From 9b58bec76e8f80664a849ed788e30503463a8eb8 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 26 Jun 2014 13:24:33 +0200 Subject: [PATCH 04/82] Documentation: devicetree: Update samsung UART bindings The primary purpose of this patch is to add information about (now required) aliases of UART ports. However the documentation currently is heavily outdated and so this patch also takes care of this. Signed-off-by: Tomasz Figa Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/samsung_uart.txt | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.txt b/Documentation/devicetree/bindings/serial/samsung_uart.txt index 2c8a17cf5cb5..85e8ee2a17fc 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.txt +++ b/Documentation/devicetree/bindings/serial/samsung_uart.txt @@ -1,14 +1,54 @@ * Samsung's UART Controller -The Samsung's UART controller is used for interfacing SoC with serial communicaion -devices. +The Samsung's UART controller is used for interfacing SoC with serial +communicaion devices. Required properties: -- compatible: should be - - "samsung,exynos4210-uart", for UART's compatible with Exynos4210 uart ports. +- compatible: should be one of following: + - "samsung,exynos4210-uart" - Exynos4210 SoC, + - "samsung,s3c2410-uart" - compatible with ports present on S3C2410 SoC, + - "samsung,s3c2412-uart" - compatible with ports present on S3C2412 SoC, + - "samsung,s3c2440-uart" - compatible with ports present on S3C2440 SoC, + - "samsung,s3c6400-uart" - compatible with ports present on S3C6400 SoC, + - "samsung,s5pv210-uart" - compatible with ports present on S5PV210 SoC. - reg: base physical address of the controller and length of memory mapped region. -- interrupts: interrupt number to the cpu. The interrupt specifier format depends - on the interrupt controller parent. +- interrupts: a single interrupt signal to SoC interrupt controller, + according to interrupt bindings documentation [1]. + +- clock-names: input names of clocks used by the controller: + - "uart" - controller bus clock, + - "clk_uart_baudN" - Nth baud base clock input (N = 0, 1, ...), + according to SoC User's Manual (only N = 0 is allowedfor SoCs without + internal baud clock mux). +- clocks: phandles and specifiers for all clocks specified in "clock-names" + property, in the same order, according to clock bindings documentation [2]. + +[1] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[2] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Note: Each Samsung UART should have an alias correctly numbered in the +"aliases" node, according to serialN format, where N is the port number +(non-negative decimal integer) as specified by User's Manual of respective +SoC. + +Example: + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + }; + +Example: + uart1: serial@7f005400 { + compatible = "samsung,s3c6400-uart"; + reg = <0x7f005400 0x100>; + interrupt-parent = <&vic1>; + interrupts = <6>; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clocks PCLK_UART1>, <&clocks PCLK_UART1>, + <&clocks SCLK_UART>; + }; From 13a9f6c64fdc55eb6c5e129c1f56cb022613a96f Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 26 Jun 2014 13:24:34 +0200 Subject: [PATCH 05/82] serial: samsung: Consider DT alias when probing ports Current driver code relies on probe order of particular samsung-uart instances, which makes it impossible to get proper initialization of ports when not all ports are available on board, not even saying of deterministic device naming. This patch fixes this on DT-enabled systems by using DT aliases for ports as instance ID, if specified, or falling back to legacy method otherwise to provide backwards compatibility. Signed-off-by: Tomasz Figa Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index bf9301094c41..be405c6115ca 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1275,11 +1275,18 @@ static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data( static int s3c24xx_serial_probe(struct platform_device *pdev) { struct s3c24xx_uart_port *ourport; + int index = probe_index; int ret; - dbg("s3c24xx_serial_probe(%p) %d\n", pdev, probe_index); + if (pdev->dev.of_node) { + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (ret >= 0) + index = ret; + } - ourport = &s3c24xx_serial_ports[probe_index]; + dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index); + + ourport = &s3c24xx_serial_ports[index]; ourport->drv_data = s3c24xx_get_driver_data(pdev); if (!ourport->drv_data) { @@ -1295,7 +1302,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ourport->port.fifosize = (ourport->info->fifosize) ? ourport->info->fifosize : - ourport->drv_data->fifosize[probe_index]; + ourport->drv_data->fifosize[index]; probe_index++; From 1e64f48ea7c59fb94acd7551dd9fa68b8a752efc Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 26 Jun 2014 13:24:35 +0200 Subject: [PATCH 06/82] ARM: dts: SAMSUNG: Add aliases of UART nodes This patch adds alias entries for UART nodes of all SoCs using samsung-uart compatible UART controllers, so that the dependency on probe order is removed and deterministic device naming is assured. Signed-off-by: Tomasz Figa Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/exynos3250.dtsi | 2 ++ arch/arm/boot/dts/exynos4.dtsi | 12 ++++++++---- arch/arm/boot/dts/exynos5.dtsi | 15 +++++++++++---- arch/arm/boot/dts/exynos5260.dtsi | 4 ++++ arch/arm/boot/dts/exynos5410.dtsi | 6 ++++++ arch/arm/boot/dts/exynos5440.dtsi | 6 ++++-- arch/arm/boot/dts/s3c2416.dtsi | 6 +++++- arch/arm/boot/dts/s3c24xx.dtsi | 9 ++++++--- arch/arm/boot/dts/s3c64xx.dtsi | 4 ++++ 9 files changed, 50 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi index 3e678fa335bf..f4b54117d22e 100644 --- a/arch/arm/boot/dts/exynos3250.dtsi +++ b/arch/arm/boot/dts/exynos3250.dtsi @@ -39,6 +39,8 @@ aliases { i2c5 = &i2c_5; i2c6 = &i2c_6; i2c7 = &i2c_7; + serial0 = &serial_0; + serial1 = &serial_1; }; cpus { diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index fbaf426d2daa..536d3c3553b2 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -44,6 +44,10 @@ aliases { fimc1 = &fimc_1; fimc2 = &fimc_2; fimc3 = &fimc_3; + serial0 = &serial_0; + serial1 = &serial_1; + serial2 = &serial_2; + serial3 = &serial_3; }; clock_audss: clock-controller@03810000 { @@ -363,7 +367,7 @@ mfc: codec@13400000 { status = "disabled"; }; - serial@13800000 { + serial_0: serial@13800000 { compatible = "samsung,exynos4210-uart"; reg = <0x13800000 0x100>; interrupts = <0 52 0>; @@ -372,7 +376,7 @@ serial@13800000 { status = "disabled"; }; - serial@13810000 { + serial_1: serial@13810000 { compatible = "samsung,exynos4210-uart"; reg = <0x13810000 0x100>; interrupts = <0 53 0>; @@ -381,7 +385,7 @@ serial@13810000 { status = "disabled"; }; - serial@13820000 { + serial_2: serial@13820000 { compatible = "samsung,exynos4210-uart"; reg = <0x13820000 0x100>; interrupts = <0 54 0>; @@ -390,7 +394,7 @@ serial@13820000 { status = "disabled"; }; - serial@13830000 { + serial_3: serial@13830000 { compatible = "samsung,exynos4210-uart"; reg = <0x13830000 0x100>; interrupts = <0 55 0>; diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi index 79d0608d6dcc..ff2d2cb0f79e 100644 --- a/arch/arm/boot/dts/exynos5.dtsi +++ b/arch/arm/boot/dts/exynos5.dtsi @@ -18,6 +18,13 @@ / { interrupt-parent = <&gic>; + aliases { + serial0 = &serial_0; + serial1 = &serial_1; + serial2 = &serial_2; + serial3 = &serial_3; + }; + chipid@10000000 { compatible = "samsung,exynos4210-chipid"; reg = <0x10000000 0x100>; @@ -50,25 +57,25 @@ gic: interrupt-controller@10481000 { interrupts = <1 9 0xf04>; }; - serial@12C00000 { + serial_0: serial@12C00000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C00000 0x100>; interrupts = <0 51 0>; }; - serial@12C10000 { + serial_1: serial@12C10000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C10000 0x100>; interrupts = <0 52 0>; }; - serial@12C20000 { + serial_2: serial@12C20000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C20000 0x100>; interrupts = <0 53 0>; }; - serial@12C30000 { + serial_3: serial@12C30000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C30000 0x100>; interrupts = <0 54 0>; diff --git a/arch/arm/boot/dts/exynos5260.dtsi b/arch/arm/boot/dts/exynos5260.dtsi index 5398a60207ca..4539a0ae714d 100644 --- a/arch/arm/boot/dts/exynos5260.dtsi +++ b/arch/arm/boot/dts/exynos5260.dtsi @@ -21,6 +21,10 @@ aliases { pinctrl0 = &pinctrl_0; pinctrl1 = &pinctrl_1; pinctrl2 = &pinctrl_2; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; }; cpus { diff --git a/arch/arm/boot/dts/exynos5410.dtsi b/arch/arm/boot/dts/exynos5410.dtsi index 3839c26f467f..52070e54589a 100644 --- a/arch/arm/boot/dts/exynos5410.dtsi +++ b/arch/arm/boot/dts/exynos5410.dtsi @@ -20,6 +20,12 @@ / { compatible = "samsung,exynos5410", "samsung,exynos5"; interrupt-parent = <&gic>; + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi index ae3a17c791f6..8f3373cd7b87 100644 --- a/arch/arm/boot/dts/exynos5440.dtsi +++ b/arch/arm/boot/dts/exynos5440.dtsi @@ -18,6 +18,8 @@ / { interrupt-parent = <&gic>; aliases { + serial0 = &serial_0; + serial1 = &serial_1; spi0 = &spi_0; tmuctrl0 = &tmuctrl_0; tmuctrl1 = &tmuctrl_1; @@ -102,7 +104,7 @@ cpufreq@160000 { >; }; - serial@B0000 { + serial_0: serial@B0000 { compatible = "samsung,exynos4210-uart"; reg = <0xB0000 0x1000>; interrupts = <0 2 0>; @@ -110,7 +112,7 @@ serial@B0000 { clock-names = "uart", "clk_uart_baud0"; }; - serial@C0000 { + serial_1: serial@C0000 { compatible = "samsung,exynos4210-uart"; reg = <0xC0000 0x1000>; interrupts = <0 3 0>; diff --git a/arch/arm/boot/dts/s3c2416.dtsi b/arch/arm/boot/dts/s3c2416.dtsi index 955e4a4f8c31..30b8f7e47454 100644 --- a/arch/arm/boot/dts/s3c2416.dtsi +++ b/arch/arm/boot/dts/s3c2416.dtsi @@ -16,6 +16,10 @@ / { model = "Samsung S3C2416 SoC"; compatible = "samsung,s3c2416"; + aliases { + serial3 = &uart3; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -68,7 +72,7 @@ serial@50008000 { <&clocks SCLK_UART>; }; - serial@5000C000 { + uart3: serial@5000C000 { compatible = "samsung,s3c2440-uart"; reg = <0x5000C000 0x4000>; interrupts = <1 18 24 4>, <1 18 25 4>; diff --git a/arch/arm/boot/dts/s3c24xx.dtsi b/arch/arm/boot/dts/s3c24xx.dtsi index 2d1d7dc9418a..5ed43b857cc4 100644 --- a/arch/arm/boot/dts/s3c24xx.dtsi +++ b/arch/arm/boot/dts/s3c24xx.dtsi @@ -16,6 +16,9 @@ / { aliases { pinctrl0 = &pinctrl_0; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; }; intc:interrupt-controller@4a000000 { @@ -46,21 +49,21 @@ timer@51000000 { #pwm-cells = <4>; }; - serial@50000000 { + uart0: serial@50000000 { compatible = "samsung,s3c2410-uart"; reg = <0x50000000 0x4000>; interrupts = <1 28 0 4>, <1 28 1 4>; status = "disabled"; }; - serial@50004000 { + uart1: serial@50004000 { compatible = "samsung,s3c2410-uart"; reg = <0x50004000 0x4000>; interrupts = <1 23 3 4>, <1 23 4 4>; status = "disabled"; }; - serial@50008000 { + uart2: serial@50008000 { compatible = "samsung,s3c2410-uart"; reg = <0x50008000 0x4000>; interrupts = <1 15 6 4>, <1 15 7 4>; diff --git a/arch/arm/boot/dts/s3c64xx.dtsi b/arch/arm/boot/dts/s3c64xx.dtsi index 4e3be4d3493d..ff5bdaac987a 100644 --- a/arch/arm/boot/dts/s3c64xx.dtsi +++ b/arch/arm/boot/dts/s3c64xx.dtsi @@ -23,6 +23,10 @@ / { aliases { i2c0 = &i2c0; pinctrl0 = &pinctrl0; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; }; cpus { From 1570a5386d84b5226a3602caa9238313be1f6895 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Tue, 1 Jul 2014 06:32:17 +0900 Subject: [PATCH 07/82] serial: samsung: no more support for S5P6440 and S5P6450 SoCs This patch removes s5p64x0 related serial because of removing support for s5p64x0 SoCs. Signed-off-by: Kukjin Kim Cc: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 - drivers/tty/serial/samsung.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index fb57159bad3a..7039238b134f 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -238,7 +238,6 @@ config SERIAL_SAMSUNG_UARTS_4 config SERIAL_SAMSUNG_UARTS int depends on PLAT_SAMSUNG - default 6 if CPU_S5P6450 default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416 default 3 help diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index be405c6115ca..3620729f29f6 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1717,7 +1717,6 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { #endif #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) || \ - defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450) || \ defined(CONFIG_CPU_S5PC100) static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { From 953b53a71bcc47d5adebd02aa1ff63c59d8c44cb Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Tue, 1 Jul 2014 06:32:22 +0900 Subject: [PATCH 08/82] serial: samsung: no more support for S5PC100 SoC This patch removes s5pc100 related serial. Signed-off-by: Kukjin Kim Cc: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 3620729f29f6..7793b16b6877 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1716,8 +1716,7 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { #define S3C2440_SERIAL_DRV_DATA (kernel_ulong_t)NULL #endif -#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) || \ - defined(CONFIG_CPU_S5PC100) +#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C6400 UART", From 1fdc31065fdf95ded3b1960d1426e1da43b297ef Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 3 Jun 2014 18:54:43 +0400 Subject: [PATCH 09/82] serial: core: Make enable_ms() optional This patch makes enable_ms() optional, so we can eliminate a lot of empty enable_ms() implementations from driver code. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index fbf6c5ad222f..a0e2f9d63b9d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1050,6 +1050,15 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) return ret; } +static void uart_enable_ms(struct uart_port *uport) +{ + /* + * Force modem status interrupts on + */ + if (uport->ops->enable_ms) + uport->ops->enable_ms(uport); +} + /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest @@ -1073,11 +1082,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) */ spin_lock_irq(&uport->lock); memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); - - /* - * Force modem status interrupts on - */ - uport->ops->enable_ms(uport); + uart_enable_ms(uport); spin_unlock_irq(&uport->lock); add_wait_queue(&port->delta_msr_wait, &wait); @@ -1508,7 +1513,7 @@ static int uart_carrier_raised(struct tty_port *port) struct uart_port *uport = state->uart_port; int mctrl; spin_lock_irq(&uport->lock); - uport->ops->enable_ms(uport); + uart_enable_ms(uport); mctrl = uport->ops->get_mctrl(uport); spin_unlock_irq(&uport->lock); if (mctrl & TIOCM_CAR) From 8b152f1096975d012f60387b899d407e4a93b46c Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 3 Jun 2014 18:54:44 +0400 Subject: [PATCH 10/82] serial: treewide: Remove empty implementations of enable_ms() Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/21285.c | 5 ----- drivers/tty/serial/altera_jtaguart.c | 5 ----- drivers/tty/serial/altera_uart.c | 5 ----- drivers/tty/serial/apbuart.c | 6 ------ drivers/tty/serial/ar933x_uart.c | 5 ----- drivers/tty/serial/arc_uart.c | 8 -------- drivers/tty/serial/bfin_sport_uart.c | 6 ------ drivers/tty/serial/bfin_uart.c | 9 --------- drivers/tty/serial/clps711x.c | 1 - drivers/tty/serial/cpm_uart/cpm_uart_core.c | 9 --------- drivers/tty/serial/dz.c | 6 ------ drivers/tty/serial/efm32-uart.c | 6 ------ drivers/tty/serial/fsl_lpuart.c | 5 ----- drivers/tty/serial/icom.c | 6 ------ drivers/tty/serial/ioc3_serial.c | 1 - drivers/tty/serial/ioc4_serial.c | 1 - drivers/tty/serial/jsm/jsm_tty.c | 6 ------ drivers/tty/serial/lantiq.c | 6 ------ drivers/tty/serial/lpc32xx_hs.c | 7 ------- drivers/tty/serial/max310x.c | 1 - drivers/tty/serial/mcf.c | 7 ------- drivers/tty/serial/mpsc.c | 5 ----- drivers/tty/serial/mrst_max3110.c | 5 ----- drivers/tty/serial/mux.c | 11 ----------- drivers/tty/serial/mxs-auart.c | 6 ------ drivers/tty/serial/nwpserial.c | 6 ------ drivers/tty/serial/samsung.c | 5 ----- drivers/tty/serial/sc16is7xx.c | 1 - drivers/tty/serial/sccnxp.c | 6 ------ drivers/tty/serial/serial_txx9.c | 6 ------ drivers/tty/serial/sh-sci.c | 8 -------- drivers/tty/serial/sn_console.c | 10 ---------- drivers/tty/serial/st-asc.c | 7 ------- drivers/tty/serial/sunhv.c | 6 ------ drivers/tty/serial/sunsab.c | 7 ------- drivers/tty/serial/tilegx.c | 10 ---------- drivers/tty/serial/timbuart.c | 6 ------ drivers/tty/serial/uartlite.c | 6 ------ drivers/tty/serial/ucc_uart.c | 11 ----------- drivers/tty/serial/xilinx_uartps.c | 6 ------ 40 files changed, 239 deletions(-) diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index c7e8b60b6177..9b208bd686e6 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -78,10 +78,6 @@ static void serial21285_stop_rx(struct uart_port *port) } } -static void serial21285_enable_ms(struct uart_port *port) -{ -} - static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; @@ -345,7 +341,6 @@ static struct uart_ops serial21285_ops = { .stop_tx = serial21285_stop_tx, .start_tx = serial21285_start_tx, .stop_rx = serial21285_stop_rx, - .enable_ms = serial21285_enable_ms, .break_ctl = serial21285_break_ctl, .startup = serial21285_startup, .shutdown = serial21285_shutdown, diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 59b3da9bcc3f..e7d1aaf07294 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -109,10 +109,6 @@ static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state) { } -static void altera_jtaguart_enable_ms(struct uart_port *port) -{ -} - static void altera_jtaguart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -291,7 +287,6 @@ static struct uart_ops altera_jtaguart_ops = { .start_tx = altera_jtaguart_start_tx, .stop_tx = altera_jtaguart_stop_tx, .stop_rx = altera_jtaguart_stop_rx, - .enable_ms = altera_jtaguart_enable_ms, .break_ctl = altera_jtaguart_break_ctl, .startup = altera_jtaguart_startup, .shutdown = altera_jtaguart_shutdown, diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 323376668b72..4c1eae93110c 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -163,10 +163,6 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state) spin_unlock_irqrestore(&port->lock, flags); } -static void altera_uart_enable_ms(struct uart_port *port) -{ -} - static void altera_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -415,7 +411,6 @@ static struct uart_ops altera_uart_ops = { .start_tx = altera_uart_start_tx, .stop_tx = altera_uart_stop_tx, .stop_rx = altera_uart_stop_rx, - .enable_ms = altera_uart_enable_ms, .break_ctl = altera_uart_break_ctl, .startup = altera_uart_startup, .shutdown = altera_uart_shutdown, diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index de11ab8ffd91..a34a0cec1685 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -71,11 +71,6 @@ static void apbuart_stop_rx(struct uart_port *port) UART_PUT_CTRL(port, cr); } -static void apbuart_enable_ms(struct uart_port *port) -{ - /* No modem status change interrupts for APBUART */ -} - static void apbuart_rx_chars(struct uart_port *port) { unsigned int status, ch, rsr, flag; @@ -337,7 +332,6 @@ static struct uart_ops grlib_apbuart_ops = { .stop_tx = apbuart_stop_tx, .start_tx = apbuart_start_tx, .stop_rx = apbuart_stop_rx, - .enable_ms = apbuart_enable_ms, .break_ctl = apbuart_break_ctl, .startup = apbuart_startup, .shutdown = apbuart_shutdown, diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index acd03af7cd52..0be1c45efd65 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -176,10 +176,6 @@ static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) spin_unlock_irqrestore(&up->port.lock, flags); } -static void ar933x_uart_enable_ms(struct uart_port *port) -{ -} - /* * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17)) */ @@ -495,7 +491,6 @@ static struct uart_ops ar933x_uart_ops = { .stop_tx = ar933x_uart_stop_tx, .start_tx = ar933x_uart_start_tx, .stop_rx = ar933x_uart_stop_rx, - .enable_ms = ar933x_uart_enable_ms, .break_ctl = ar933x_uart_break_ctl, .startup = ar933x_uart_startup, .shutdown = ar933x_uart_shutdown, diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index c9f5c9dcc15c..643658f2b5b2 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -340,13 +340,6 @@ static void arc_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) /* MCR not present */ } -/* Enable Modem Status Interrupts */ - -static void arc_serial_enable_ms(struct uart_port *port) -{ - /* MSR not present */ -} - static void arc_serial_break_ctl(struct uart_port *port, int break_state) { /* ARC UART doesn't support sending Break signal */ @@ -510,7 +503,6 @@ static struct uart_ops arc_serial_pops = { .stop_tx = arc_serial_stop_tx, .start_tx = arc_serial_start_tx, .stop_rx = arc_serial_stop_rx, - .enable_ms = arc_serial_enable_ms, .break_ctl = arc_serial_break_ctl, .startup = arc_serial_startup, .shutdown = arc_serial_shutdown, diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index 4f229703328b..1174efa466a6 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -426,11 +426,6 @@ static void sport_stop_rx(struct uart_port *port) SSYNC(); } -static void sport_enable_ms(struct uart_port *port) -{ - pr_debug("%s enter\n", __func__); -} - static void sport_break_ctl(struct uart_port *port, int break_state) { pr_debug("%s enter\n", __func__); @@ -587,7 +582,6 @@ struct uart_ops sport_uart_ops = { .stop_tx = sport_stop_tx, .start_tx = sport_start_tx, .stop_rx = sport_stop_rx, - .enable_ms = sport_enable_ms, .break_ctl = sport_break_ctl, .startup = sport_startup, .shutdown = sport_shutdown, diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index ac86a20992e9..dddc081568f1 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -200,14 +200,6 @@ static void bfin_serial_stop_rx(struct uart_port *port) UART_CLEAR_IER(uart, ERBFI); } -/* - * Set the modem control timer to fire immediately. - */ -static void bfin_serial_enable_ms(struct uart_port *port) -{ -} - - #if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO) # define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold) # define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v)) @@ -1014,7 +1006,6 @@ static struct uart_ops bfin_serial_pops = { .stop_tx = bfin_serial_stop_tx, .start_tx = bfin_serial_start_tx, .stop_rx = bfin_serial_stop_rx, - .enable_ms = bfin_serial_enable_ms, .break_ctl = bfin_serial_break_ctl, .startup = bfin_serial_startup, .shutdown = bfin_serial_shutdown, diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 14aaea0d4131..f5b4c3d7e38f 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -352,7 +352,6 @@ static const struct uart_ops uart_clps711x_ops = { .stop_tx = uart_clps711x_stop_tx, .start_tx = uart_clps711x_start_tx, .stop_rx = uart_clps711x_nop_void, - .enable_ms = uart_clps711x_nop_void, .break_ctl = uart_clps711x_break_ctl, .set_ldisc = uart_clps711x_set_ldisc, .startup = uart_clps711x_startup, diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index aa60e6d13eca..533852eb8778 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -201,14 +201,6 @@ static void cpm_uart_stop_rx(struct uart_port *port) clrbits16(&sccp->scc_sccm, UART_SCCM_RX); } -/* - * Enable Modem status interrupts - */ -static void cpm_uart_enable_ms(struct uart_port *port) -{ - pr_debug("CPM uart[%d]:enable ms\n", port->line); -} - /* * Generate a break. */ @@ -1122,7 +1114,6 @@ static struct uart_ops cpm_uart_pops = { .stop_tx = cpm_uart_stop_tx, .start_tx = cpm_uart_start_tx, .stop_rx = cpm_uart_stop_rx, - .enable_ms = cpm_uart_enable_ms, .break_ctl = cpm_uart_break_ctl, .startup = cpm_uart_startup, .shutdown = cpm_uart_shutdown, diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index cdbbc788230a..c121f16a973f 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -151,11 +151,6 @@ static void dz_stop_rx(struct uart_port *uport) dz_out(dport, DZ_LPR, dport->cflag); } -static void dz_enable_ms(struct uart_port *uport) -{ - /* nothing to do */ -} - /* * ------------------------------------------------------------ * @@ -751,7 +746,6 @@ static struct uart_ops dz_ops = { .stop_tx = dz_stop_tx, .start_tx = dz_start_tx, .stop_rx = dz_stop_rx, - .enable_ms = dz_enable_ms, .break_ctl = dz_break_ctl, .startup = dz_startup, .shutdown = dz_shutdown, diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 3b0ee9afd76f..7baa34920dbf 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -185,11 +185,6 @@ static void efm32_uart_stop_rx(struct uart_port *port) efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD); } -static void efm32_uart_enable_ms(struct uart_port *port) -{ - /* no handshake lines, no modem status interrupts */ -} - static void efm32_uart_break_ctl(struct uart_port *port, int ctl) { /* not possible without fiddling with gpios */ @@ -499,7 +494,6 @@ static struct uart_ops efm32_uart_pops = { .stop_tx = efm32_uart_stop_tx, .start_tx = efm32_uart_start_tx, .stop_rx = efm32_uart_stop_rx, - .enable_ms = efm32_uart_enable_ms, .break_ctl = efm32_uart_break_ctl, .startup = efm32_uart_startup, .shutdown = efm32_uart_shutdown, diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 49385c86cfba..c5ad567cab8d 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -179,10 +179,6 @@ static void lpuart_stop_rx(struct uart_port *port) writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2); } -static void lpuart_enable_ms(struct uart_port *port) -{ -} - static void lpuart_copy_rx_to_tty(struct lpuart_port *sport, struct tty_port *tty, int count) { @@ -996,7 +992,6 @@ static struct uart_ops lpuart_pops = { .stop_tx = lpuart_stop_tx, .start_tx = lpuart_start_tx, .stop_rx = lpuart_stop_rx, - .enable_ms = lpuart_enable_ms, .break_ctl = lpuart_break_ctl, .startup = lpuart_startup, .shutdown = lpuart_shutdown, diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 67423805e6d9..d4620fe5da2e 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1052,11 +1052,6 @@ static void icom_stop_rx(struct uart_port *port) writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); } -static void icom_enable_ms(struct uart_port *port) -{ - /* no-op */ -} - static void icom_break(struct uart_port *port, int break_state) { unsigned char cmdReg; @@ -1300,7 +1295,6 @@ static struct uart_ops icom_ops = { .start_tx = icom_start_tx, .send_xchar = icom_send_xchar, .stop_rx = icom_stop_rx, - .enable_ms = icom_enable_ms, .break_ctl = icom_break, .startup = icom_open, .shutdown = icom_close, diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c index 6e4c715c5d26..abd7ea26ed9a 100644 --- a/drivers/tty/serial/ioc3_serial.c +++ b/drivers/tty/serial/ioc3_serial.c @@ -1880,7 +1880,6 @@ static struct uart_ops ioc3_ops = { .stop_tx = ic3_stop_tx, .start_tx = ic3_start_tx, .stop_rx = ic3_stop_rx, - .enable_ms = null_void_function, .break_ctl = ic3_break_ctl, .startup = ic3_startup, .shutdown = ic3_shutdown, diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index 1274499850fc..aa28209f44c1 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -2597,7 +2597,6 @@ static struct uart_ops ioc4_ops = { .stop_tx = ic4_stop_tx, .start_tx = ic4_start_tx, .stop_rx = null_void_function, - .enable_ms = null_void_function, .break_ctl = ic4_break_ctl, .startup = ic4_startup, .shutdown = ic4_shutdown, diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 27bb75070c96..3e5c1563afe2 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -177,11 +177,6 @@ static void jsm_tty_stop_rx(struct uart_port *port) channel->ch_bd->bd_ops->disable_receiver(channel); } -static void jsm_tty_enable_ms(struct uart_port *port) -{ - /* Nothing needed */ -} - static void jsm_tty_break(struct uart_port *port, int break_state) { unsigned long lock_flags; @@ -354,7 +349,6 @@ static struct uart_ops jsm_ops = { .start_tx = jsm_tty_start_tx, .send_xchar = jsm_tty_send_xchar, .stop_rx = jsm_tty_stop_rx, - .enable_ms = jsm_tty_enable_ms, .break_ctl = jsm_tty_break, .startup = jsm_tty_open, .shutdown = jsm_tty_close, diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 88d01e0bb0c8..ea030830cfa2 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -154,11 +154,6 @@ lqasc_stop_rx(struct uart_port *port) ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); } -static void -lqasc_enable_ms(struct uart_port *port) -{ -} - static int lqasc_rx_chars(struct uart_port *port) { @@ -568,7 +563,6 @@ static struct uart_ops lqasc_pops = { .stop_tx = lqasc_stop_tx, .start_tx = lqasc_start_tx, .stop_rx = lqasc_stop_rx, - .enable_ms = lqasc_enable_ms, .break_ctl = lqasc_break_ctl, .startup = lqasc_startup, .shutdown = lqasc_shutdown, diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 701644f06820..6f0f89282847 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -427,12 +427,6 @@ static void serial_lpc32xx_stop_rx(struct uart_port *port) LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase)); } -/* port->lock held by caller. */ -static void serial_lpc32xx_enable_ms(struct uart_port *port) -{ - /* Modem status is not supported */ -} - /* port->lock is not held. */ static void serial_lpc32xx_break_ctl(struct uart_port *port, int break_state) @@ -658,7 +652,6 @@ static struct uart_ops serial_lpc32xx_pops = { .stop_tx = serial_lpc32xx_stop_tx, .start_tx = serial_lpc32xx_start_tx, .stop_rx = serial_lpc32xx_stop_rx, - .enable_ms = serial_lpc32xx_enable_ms, .break_ctl = serial_lpc32xx_break_ctl, .startup = serial_lpc32xx_startup, .shutdown = serial_lpc32xx_shutdown, diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ba285cd45b59..82573dc4d8cf 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1008,7 +1008,6 @@ static const struct uart_ops max310x_ops = { .stop_tx = max310x_null_void, .start_tx = max310x_start_tx, .stop_rx = max310x_null_void, - .enable_ms = max310x_null_void, .break_ctl = max310x_break_ctl, .startup = max310x_startup, .shutdown = max310x_shutdown, diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index a6f085717f94..fab4d6ad16ef 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -150,12 +150,6 @@ static void mcf_break_ctl(struct uart_port *port, int break_state) /****************************************************************************/ -static void mcf_enable_ms(struct uart_port *port) -{ -} - -/****************************************************************************/ - static int mcf_startup(struct uart_port *port) { struct mcf_uart *pp = container_of(port, struct mcf_uart, port); @@ -507,7 +501,6 @@ static const struct uart_ops mcf_uart_ops = { .start_tx = mcf_start_tx, .stop_tx = mcf_stop_tx, .stop_rx = mcf_stop_rx, - .enable_ms = mcf_enable_ms, .break_ctl = mcf_break_ctl, .startup = mcf_startup, .shutdown = mcf_shutdown, diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index 759c6a6fa74a..ae49856ef6c7 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -1336,10 +1336,6 @@ static void mpsc_stop_rx(struct uart_port *port) mpsc_sdma_cmd(pi, SDMA_SDCM_AR); } -static void mpsc_enable_ms(struct uart_port *port) -{ -} - static void mpsc_break_ctl(struct uart_port *port, int ctl) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; @@ -1674,7 +1670,6 @@ static struct uart_ops mpsc_pops = { .stop_tx = mpsc_stop_tx, .start_tx = mpsc_start_tx, .stop_rx = mpsc_stop_rx, - .enable_ms = mpsc_enable_ms, .break_ctl = mpsc_break_ctl, .startup = mpsc_startup, .shutdown = mpsc_shutdown, diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index db0448ae59dc..1504a14ec1a6 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -698,10 +698,6 @@ static void serial_m3110_pm(struct uart_port *port, unsigned int state, { } -static void serial_m3110_enable_ms(struct uart_port *port) -{ -} - static struct uart_ops serial_m3110_ops = { .tx_empty = serial_m3110_tx_empty, .set_mctrl = serial_m3110_set_mctrl, @@ -709,7 +705,6 @@ static struct uart_ops serial_m3110_ops = { .stop_tx = serial_m3110_stop_tx, .start_tx = serial_m3110_start_tx, .stop_rx = serial_m3110_stop_rx, - .enable_ms = serial_m3110_enable_ms, .break_ctl = serial_m3110_break_ctl, .startup = serial_m3110_startup, .shutdown = serial_m3110_shutdown, diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index be127d0da32c..dd26511ad875 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -168,16 +168,6 @@ static void mux_stop_rx(struct uart_port *port) { } -/** - * mux_enable_ms - Enable modum status interrupts. - * @port: Ptr to the uart_port. - * - * The Serial Mux does not support this function. - */ -static void mux_enable_ms(struct uart_port *port) -{ -} - /** * mux_break_ctl - Control the transmitssion of a break signal. * @port: Ptr to the uart_port. @@ -449,7 +439,6 @@ static struct uart_ops mux_pops = { .stop_tx = mux_stop_tx, .start_tx = mux_start_tx, .stop_rx = mux_stop_rx, - .enable_ms = mux_enable_ms, .break_ctl = mux_break_ctl, .startup = mux_startup, .shutdown = mux_shutdown, diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 86de4477d98a..b5c329248c81 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -815,17 +815,11 @@ static void mxs_auart_break_ctl(struct uart_port *u, int ctl) u->membase + AUART_LINECTRL_CLR); } -static void mxs_auart_enable_ms(struct uart_port *port) -{ - /* just empty */ -} - static struct uart_ops mxs_auart_ops = { .tx_empty = mxs_auart_tx_empty, .start_tx = mxs_auart_start_tx, .stop_tx = mxs_auart_stop_tx, .stop_rx = mxs_auart_stop_rx, - .enable_ms = mxs_auart_enable_ms, .break_ctl = mxs_auart_break_ctl, .set_mctrl = mxs_auart_set_mctrl, .get_mctrl = mxs_auart_get_mctrl, diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c index 693bc6c2561e..c06366b6bc29 100644 --- a/drivers/tty/serial/nwpserial.c +++ b/drivers/tty/serial/nwpserial.c @@ -240,11 +240,6 @@ static void nwpserial_break_ctl(struct uart_port *port, int ctl) /* N/A */ } -static void nwpserial_enable_ms(struct uart_port *port) -{ - /* N/A */ -} - static void nwpserial_stop_rx(struct uart_port *port) { struct nwpserial_port *up; @@ -315,7 +310,6 @@ static struct uart_ops nwpserial_pops = { .stop_tx = nwpserial_stop_tx, .start_tx = nwpserial_start_tx, .stop_rx = nwpserial_stop_rx, - .enable_ms = nwpserial_enable_ms, .break_ctl = nwpserial_break_ctl, .startup = nwpserial_startup, .shutdown = nwpserial_shutdown, diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 7793b16b6877..eadab074e7c9 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -203,10 +203,6 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) } } -static void s3c24xx_serial_enable_ms(struct uart_port *port) -{ -} - static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port) { return to_ourport(port)->info; @@ -952,7 +948,6 @@ static struct uart_ops s3c24xx_serial_ops = { .stop_tx = s3c24xx_serial_stop_tx, .start_tx = s3c24xx_serial_start_tx, .stop_rx = s3c24xx_serial_stop_rx, - .enable_ms = s3c24xx_serial_enable_ms, .break_ctl = s3c24xx_serial_break_ctl, .startup = s3c24xx_serial_startup, .shutdown = s3c24xx_serial_shutdown, diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 1b6a77c4b2cb..914825e03427 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -991,7 +991,6 @@ static const struct uart_ops sc16is7xx_ops = { .stop_tx = sc16is7xx_stop_tx, .start_tx = sc16is7xx_start_tx, .stop_rx = sc16is7xx_stop_rx, - .enable_ms = sc16is7xx_null_void, .break_ctl = sc16is7xx_break_ctl, .startup = sc16is7xx_startup, .shutdown = sc16is7xx_shutdown, diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index e84b6a3bdd18..75850f70b479 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -533,11 +533,6 @@ static unsigned int sccnxp_tx_empty(struct uart_port *port) return (val & SR_TXEMT) ? TIOCSER_TEMT : 0; } -static void sccnxp_enable_ms(struct uart_port *port) -{ - /* Do nothing */ -} - static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct sccnxp_port *s = dev_get_drvdata(port->dev); @@ -790,7 +785,6 @@ static const struct uart_ops sccnxp_ops = { .stop_tx = sccnxp_stop_tx, .start_tx = sccnxp_start_tx, .stop_rx = sccnxp_stop_rx, - .enable_ms = sccnxp_enable_ms, .break_ctl = sccnxp_break_ctl, .startup = sccnxp_startup, .shutdown = sccnxp_shutdown, diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index ea8546092c7e..29f5232f79e4 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -244,11 +244,6 @@ static void serial_txx9_stop_rx(struct uart_port *port) up->port.read_status_mask &= ~TXX9_SIDISR_RDIS; } -static void serial_txx9_enable_ms(struct uart_port *port) -{ - /* TXX9-SIO can not control DTR... */ -} - static void serial_txx9_initialize(struct uart_port *port) { struct uart_txx9_port *up = to_uart_txx9_port(port); @@ -858,7 +853,6 @@ static struct uart_ops serial_txx9_pops = { .stop_tx = serial_txx9_stop_tx, .start_tx = serial_txx9_start_tx, .stop_rx = serial_txx9_stop_rx, - .enable_ms = serial_txx9_enable_ms, .break_ctl = serial_txx9_break_ctl, .startup = serial_txx9_startup, .shutdown = serial_txx9_shutdown, diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 88236da0ddf7..26dad3e87b52 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1560,13 +1560,6 @@ static void sci_stop_rx(struct uart_port *port) serial_port_out(port, SCSCR, ctrl); } -static void sci_enable_ms(struct uart_port *port) -{ - /* - * Not supported by hardware, always a nop. - */ -} - static void sci_break_ctl(struct uart_port *port, int break_state) { struct sci_port *s = to_sci_port(port); @@ -2080,7 +2073,6 @@ static struct uart_ops sci_uart_ops = { .start_tx = sci_start_tx, .stop_tx = sci_stop_tx, .stop_rx = sci_stop_rx, - .enable_ms = sci_enable_ms, .break_ctl = sci_break_ctl, .startup = sci_startup, .shutdown = sci_shutdown, diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c index f51ffdc696fd..33e94e56dcdb 100644 --- a/drivers/tty/serial/sn_console.c +++ b/drivers/tty/serial/sn_console.c @@ -274,15 +274,6 @@ static void snp_release_port(struct uart_port *port) { } -/** - * snp_enable_ms - Force modem status interrupts on - no-op for us - * @port: Port to operate on - we ignore - no-op function - * - */ -static void snp_enable_ms(struct uart_port *port) -{ -} - /** * snp_shutdown - shut down the port - free irq and disable - no-op for us * @port: Port to shut down - we ignore @@ -396,7 +387,6 @@ static struct uart_ops sn_console_ops = { .stop_tx = snp_stop_tx, .start_tx = snp_start_tx, .stop_rx = snp_stop_rx, - .enable_ms = snp_enable_ms, .break_ctl = snp_break_ctl, .startup = snp_startup, .shutdown = snp_shutdown, diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index f48b1cc07eea..2bee4fbccba1 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -411,12 +411,6 @@ static void asc_stop_rx(struct uart_port *port) asc_disable_rx_interrupts(port); } -/* Force modem status interrupts on */ -static void asc_enable_ms(struct uart_port *port) -{ - /* Nothing here yet .. */ -} - /* Handle breaks - ignored by us */ static void asc_break_ctl(struct uart_port *port, int break_state) { @@ -644,7 +638,6 @@ static struct uart_ops asc_uart_ops = { .start_tx = asc_start_tx, .stop_tx = asc_stop_tx, .stop_rx = asc_stop_rx, - .enable_ms = asc_enable_ms, .break_ctl = asc_break_ctl, .startup = asc_startup, .shutdown = asc_shutdown, diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index dc697cee248a..20521db2189f 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -285,11 +285,6 @@ static void sunhv_stop_rx(struct uart_port *port) { } -/* port->lock held by caller. */ -static void sunhv_enable_ms(struct uart_port *port) -{ -} - /* port->lock is not held. */ static void sunhv_break_ctl(struct uart_port *port, int break_state) { @@ -379,7 +374,6 @@ static struct uart_ops sunhv_pops = { .start_tx = sunhv_start_tx, .send_xchar = sunhv_send_xchar, .stop_rx = sunhv_stop_rx, - .enable_ms = sunhv_enable_ms, .break_ctl = sunhv_break_ctl, .startup = sunhv_startup, .shutdown = sunhv_shutdown, diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 80a58eca785b..c9751d8b24c1 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -473,12 +473,6 @@ static void sunsab_stop_rx(struct uart_port *port) writeb(up->interrupt_mask1, &up->regs->w.imr0); } -/* port->lock held by caller. */ -static void sunsab_enable_ms(struct uart_port *port) -{ - /* For now we always receive these interrupts. */ -} - /* port->lock is not held. */ static void sunsab_break_ctl(struct uart_port *port, int break_state) { @@ -807,7 +801,6 @@ static struct uart_ops sunsab_pops = { .start_tx = sunsab_start_tx, .send_xchar = sunsab_send_xchar, .stop_rx = sunsab_stop_rx, - .enable_ms = sunsab_enable_ms, .break_ctl = sunsab_break_ctl, .startup = sunsab_startup, .shutdown = sunsab_shutdown, diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c index 613ccf09dc2a..453215f5420d 100644 --- a/drivers/tty/serial/tilegx.c +++ b/drivers/tty/serial/tilegx.c @@ -314,15 +314,6 @@ static void tilegx_stop_rx(struct uart_port *port) mutex_unlock(&tile_uart->mutex); } - -/* - * Enable modem status interrupts. - */ -static void tilegx_enable_ms(struct uart_port *port) -{ - /* N/A */ -} - /* * Control the transmission of a break signal. */ @@ -614,7 +605,6 @@ static const struct uart_ops tilegx_ops = { .stop_tx = tilegx_stop_tx, .start_tx = tilegx_start_tx, .stop_rx = tilegx_stop_rx, - .enable_ms = tilegx_enable_ms, .break_ctl = tilegx_break_ctl, .startup = tilegx_startup, .shutdown = tilegx_shutdown, diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index f87097acd8ab..0d11d5032b93 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -244,11 +244,6 @@ static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier) *ier |= CTS_DELTA; } -static void timbuart_enable_ms(struct uart_port *port) -{ - /* N/A */ -} - static void timbuart_break_ctl(struct uart_port *port, int ctl) { /* N/A */ @@ -405,7 +400,6 @@ static struct uart_ops timbuart_ops = { .start_tx = timbuart_start_tx, .flush_buffer = timbuart_flush_buffer, .stop_rx = timbuart_stop_rx, - .enable_ms = timbuart_enable_ms, .break_ctl = timbuart_break_ctl, .startup = timbuart_startup, .shutdown = timbuart_shutdown, diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index dce27f34937e..9fc22f40796e 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -250,11 +250,6 @@ static void ulite_stop_rx(struct uart_port *port) | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; } -static void ulite_enable_ms(struct uart_port *port) -{ - /* N/A */ -} - static void ulite_break_ctl(struct uart_port *port, int ctl) { /* N/A */ @@ -395,7 +390,6 @@ static struct uart_ops ulite_ops = { .stop_tx = ulite_stop_tx, .start_tx = ulite_start_tx, .stop_rx = ulite_stop_rx, - .enable_ms = ulite_enable_ms, .break_ctl = ulite_break_ctl, .startup = ulite_startup, .shutdown = ulite_shutdown, diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 1c52074c38df..c107a0f0e72f 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -435,16 +435,6 @@ static void qe_uart_stop_rx(struct uart_port *port) clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); } -/* - * Enable status change interrupts - * - * We don't support status change interrupts, but we need to define this - * function otherwise the kernel will panic. - */ -static void qe_uart_enable_ms(struct uart_port *port) -{ -} - /* Start or stop sending break signal * * This function controls the sending of a break signal. If break_state=1, @@ -1102,7 +1092,6 @@ static struct uart_ops qe_uart_pops = { .stop_tx = qe_uart_stop_tx, .start_tx = qe_uart_start_tx, .stop_rx = qe_uart_stop_rx, - .enable_ms = qe_uart_enable_ms, .break_ctl = qe_uart_break_ctl, .startup = qe_uart_startup, .shutdown = qe_uart_shutdown, diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 8809775e2ba3..01951d27cc03 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -918,11 +918,6 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) /* N/A */ } -static void cdns_uart_enable_ms(struct uart_port *port) -{ - /* N/A */ -} - #ifdef CONFIG_CONSOLE_POLL static int cdns_uart_poll_get_char(struct uart_port *port) { @@ -974,7 +969,6 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) static struct uart_ops cdns_uart_ops = { .set_mctrl = cdns_uart_set_mctrl, .get_mctrl = cdns_uart_get_mctrl, - .enable_ms = cdns_uart_enable_ms, .start_tx = cdns_uart_start_tx, .stop_tx = cdns_uart_stop_tx, .stop_rx = cdns_uart_stop_rx, From a9977620a448f12a7337daca452fd20e89a96e23 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 16 Jun 2014 07:33:38 +0200 Subject: [PATCH 11/82] tty: serial: men_z135_uart: Wakeup UART after transmitting Call uart_write_wakeup() after writing the hardware FIFO and updateing the FIFO pointers. This fixes high latency and jitter on PPP over Serial links. Reported-by: Jun Shih Tested-by: Jun Shih Signed-off-by: Johannes Thumshirn Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/men_z135_uart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index c9d18548783a..30e9e60bc5cd 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -308,9 +308,6 @@ static void men_z135_handle_tx(struct men_z135_port *uart) if (port->x_char) goto out; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - /* calculate bytes to copy */ qlen = uart_circ_chars_pending(xmit); if (qlen <= 0) @@ -357,6 +354,9 @@ static void men_z135_handle_tx(struct men_z135_port *uart) port->icount.tx += n; + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + irq_en: if (!uart_circ_empty(xmit)) men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); From 7282cec90365533befce1552ab09edbcd0af0dbd Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Thu, 3 Jul 2014 21:26:59 +0800 Subject: [PATCH 12/82] serial: sirf: transfer more bytes once to decrease interrupts the current codes send 1 bytes, then after getting TX done interrupt, send subsequent bytes. it causes redundant interrupts. for example, if we have 3 bytes in TX buffer, the TX flow is: 1. send 1 byte 2. get TX down interrupt 3. send the left 2 bytes 4. get TX down interrupt this patch moves to send more bytes and decrease interrupts, the new flow is: 1. send 3 bytes 2. get TX down interrupt Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sirfsoc_uart.c | 3 ++- drivers/tty/serial/sirfsoc_uart.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 9b4d71cff00d..4102192687ee 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -290,7 +290,8 @@ static void sirfsoc_uart_start_tx(struct uart_port *port) if (sirfport->tx_dma_chan) sirfsoc_uart_tx_with_dma(sirfport); else { - sirfsoc_uart_pio_tx_chars(sirfport, 1); + sirfsoc_uart_pio_tx_chars(sirfport, + SIRFSOC_UART_IO_TX_REASONABLE_CNT); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); if (!sirfport->is_marco) wr_regl(port, ureg->sirfsoc_int_en_reg, diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index 69a62ebd3afc..6a7ebf7ef130 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -449,4 +449,4 @@ struct sirfsoc_uart_port { /* I/O Mode */ #define SIRFSOC_UART_IO_RX_MAX_CNT 256 -#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 6 +#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 256 From 2b844ad2bfdb6e21e6490f3a80f67d869c10df4a Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 1 Jun 2014 15:38:24 +0200 Subject: [PATCH 13/82] tty: serial: msm_serial.c: Cleaning up uninitialized variables There is a risk that the variable will be used without being initialized. This was largely found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 72000a6d5af0..90feee190f2a 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -917,7 +917,7 @@ static int __init msm_console_setup(struct console *co, char *options) { struct uart_port *port; struct msm_port *msm_port; - int baud, flow, bits, parity; + int baud = 0, flow, bits, parity; if (unlikely(co->index >= UART_NR || co->index < 0)) return -ENXIO; From 1ff5b64dccbf23acfe7993b9132b6992922a4756 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 4 Jun 2014 20:06:41 -0300 Subject: [PATCH 14/82] serial: samsung: Use %pa to print 'resource_size_t' type When building multi_v7_defconfig with CONFIG_ARM_LPAE=y the following warning is seen: drivers/tty/serial/samsung.c: In function 's3c24xx_serial_init_port': drivers/tty/serial/samsung.c:1229:2: warning: format '%x' expects argument of type 'unsigned int', but argument 2 has type 'resource_size_t' [-Wformat] Use %pa to print 'resource_size_t' type to fix the warning. Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Reviewed-by: Jingoo Han Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index eadab074e7c9..6be852d4df6d 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1221,8 +1221,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, wr_regl(port, S3C64XX_UINTSP, 0xf); } - dbg("port: map=%08x, mem=%p, irq=%d (%d,%d), clock=%u\n", - port->mapbase, port->membase, port->irq, + dbg("port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n", + &port->mapbase, port->membase, port->irq, ourport->rx_irq, ourport->tx_irq, port->uartclk); /* reset the fifos (and setup the uart) */ From 4e26b134bd17234e373376b561d2fc5cba3fccb2 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 5 Jun 2014 16:51:40 +0300 Subject: [PATCH 15/82] serial: 8250_dw: clock rate handling for all ACPI platforms This replaces the Baytrail specific custom set_termios hook with a more generic one where the clock framework is used to set the rate. The method also doesn't need to be limited to just Baytrail, so it's used with all ACPI platforms. Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 103 ++++++++---------------------- 1 file changed, 28 insertions(+), 75 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 51b307aab75e..b8e4eb3e7cbe 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -62,70 +62,12 @@ struct dw8250_data { struct uart_8250_dma dma; }; -struct dw8250_acpi_desc { - void (*set_termios)(struct uart_port *p, struct ktermios *termios, - struct ktermios *old); -}; - #define BYT_PRV_CLK 0x800 #define BYT_PRV_CLK_EN (1 << 0) #define BYT_PRV_CLK_M_VAL_SHIFT 1 #define BYT_PRV_CLK_N_VAL_SHIFT 16 #define BYT_PRV_CLK_UPDATE (1 << 31) -static void byt_set_termios(struct uart_port *p, struct ktermios *termios, - struct ktermios *old) -{ - unsigned int baud = tty_termios_baud_rate(termios); - unsigned int m, n; - u32 reg; - - /* - * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the - * dividers must be adjusted. - * - * uartclk = (m / n) * 100 MHz, where m <= n - */ - switch (baud) { - case 500000: - case 1000000: - case 2000000: - case 4000000: - m = 64; - n = 100; - p->uartclk = 64000000; - break; - case 3500000: - m = 56; - n = 100; - p->uartclk = 56000000; - break; - case 1500000: - case 3000000: - m = 48; - n = 100; - p->uartclk = 48000000; - break; - case 2500000: - m = 40; - n = 100; - p->uartclk = 40000000; - break; - default: - m = 2304; - n = 3125; - p->uartclk = 73728000; - } - - /* Reset the clock */ - reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); - writel(reg, p->membase + BYT_PRV_CLK); - reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; - writel(reg, p->membase + BYT_PRV_CLK); - - serial8250_do_set_termios(p, termios, old); -} - static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; @@ -242,6 +184,32 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) pm_runtime_put_sync_suspend(port->dev); } +static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + struct dw8250_data *d = p->private_data; + unsigned int rate; + int ret; + + if (IS_ERR(d->clk) || !old) + goto out; + + /* Not requesting clock rates below 1.8432Mhz */ + if (baud < 115200) + baud = 115200; + + clk_disable_unprepare(d->clk); + rate = clk_round_rate(d->clk, baud * 16); + ret = clk_set_rate(d->clk, rate); + clk_prepare_enable(d->clk); + + if (!ret) + p->uartclk = rate; +out: + serial8250_do_set_termios(p, termios, old); +} + static bool dw8250_dma_filter(struct dma_chan *chan, void *param) { struct dw8250_data *data = param; @@ -340,16 +308,10 @@ static int dw8250_probe_of(struct uart_port *p, static int dw8250_probe_acpi(struct uart_8250_port *up, struct dw8250_data *data) { - const struct acpi_device_id *id; struct uart_port *p = &up->port; - struct dw8250_acpi_desc *acpi_desc; dw8250_setup_port(up); - id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); - if (!id) - return -ENODEV; - p->iotype = UPIO_MEM32; p->serial_in = dw8250_serial_in32; p->serial_out = dw8250_serial_out32; @@ -360,12 +322,7 @@ static int dw8250_probe_acpi(struct uart_8250_port *up, up->dma->rxconf.src_maxburst = p->fifosize / 4; up->dma->txconf.dst_maxburst = p->fifosize / 4; - acpi_desc = (struct dw8250_acpi_desc *)id->driver_data; - if (!acpi_desc) - return 0; - - if (acpi_desc->set_termios) - p->set_termios = acpi_desc->set_termios; + up->port.set_termios = dw8250_set_termios; return 0; } @@ -514,16 +471,12 @@ static const struct of_device_id dw8250_of_match[] = { }; MODULE_DEVICE_TABLE(of, dw8250_of_match); -static struct dw8250_acpi_desc byt_8250_desc = { - .set_termios = byt_set_termios, -}; - static const struct acpi_device_id dw8250_acpi_match[] = { { "INT33C4", 0 }, { "INT33C5", 0 }, { "INT3434", 0 }, { "INT3435", 0 }, - { "80860F0A", (kernel_ulong_t)&byt_8250_desc}, + { "80860F0A", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); From d8782c7452b4a54cc8830074e8cd967e17559880 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 6 Jun 2014 15:24:10 +0300 Subject: [PATCH 16/82] serial: 8250_dw: use UPF_* constants when define flags The flags member has upf_t type and corresponding macros to define them. This patch converts ASYNC_SKIP_TEST to UPF_SKIP_TEST in 8250_dw.c. Otherwise we got a sparse warning: drivers/tty/serial/8250/8250_dw.c:302:46: warning: restricted upf_t degrades to integer drivers/tty/serial/8250/8250_dw.c:302:62: warning: restricted upf_t degrades to integer drivers/tty/serial/8250/8250_dw.c:302:26: warning: incorrect type in assignment (different base types) drivers/tty/serial/8250/8250_dw.c:302:26: expected restricted upf_t [usertype] flags drivers/tty/serial/8250/8250_dw.c:302:26: got unsigned int Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index b8e4eb3e7cbe..a1450ae6f9c1 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -267,7 +267,7 @@ static int dw8250_probe_of(struct uart_port *p, p->membase += 7; #endif p->serial_out = dw8250_serial_out_rb; - p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; + p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; p->type = PORT_OCTEON; data->usr_reg = 0x27; has_ucv = false; From 7d78cbefaa465bbf36e2b4b90d3c196a00f54008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Mon, 16 Jun 2014 15:25:17 +0200 Subject: [PATCH 17/82] serial: 8250_dw: add ability to handle the peripheral clock First try to find the named clock variants then fall back to the already existing handling of a nameless declared baudclk. This also adds the missing documentation for this already existing variant. Signed-off-by: Heiko Stuebner Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/snps-dw-apb-uart.txt | 31 +++++++++++++++++++ drivers/tty/serial/8250/8250_dw.c | 31 +++++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt index f13f1c5be91c..095ac7172ffe 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt @@ -4,7 +4,15 @@ Required properties: - compatible : "snps,dw-apb-uart" - reg : offset and length of the register set for the device. - interrupts : should contain uart interrupt. + +Clock handling: +The clock rate of the input clock needs to be supplied by one of - clock-frequency : the input clock frequency for the UART. +- clocks : phandle to the input clock + +The supplying peripheral clock can also be handled, needing a second property +- clock-names: tuple listing input clock names. + Required elements: "baudclk", "apb_pclk" Optional properties: - reg-shift : quantity to shift the register offsets by. If this property is @@ -23,3 +31,26 @@ Example: reg-shift = <2>; reg-io-width = <4>; }; + +Example with one clock: + + uart@80230000 { + compatible = "snps,dw-apb-uart"; + reg = <0x80230000 0x100>; + clocks = <&baudclk>; + interrupts = <10>; + reg-shift = <2>; + reg-io-width = <4>; + }; + +Example with two clocks: + + uart@80230000 { + compatible = "snps,dw-apb-uart"; + reg = <0x80230000 0x100>; + clocks = <&baudclk>, <&apb_pclk>; + clock-names = "baudclk", "apb_pclk"; + interrupts = <10>; + reg-shift = <2>; + reg-io-width = <4>; + }; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a1450ae6f9c1..c531fa42f838 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -59,6 +59,7 @@ struct dw8250_data { int last_mcr; int line; struct clk *clk; + struct clk *pclk; struct uart_8250_dma dma; }; @@ -359,10 +360,25 @@ static int dw8250_probe(struct platform_device *pdev) return -ENOMEM; data->usr_reg = DW_UART_USR; - data->clk = devm_clk_get(&pdev->dev, NULL); + data->clk = devm_clk_get(&pdev->dev, "baudclk"); + if (IS_ERR(data->clk)) + data->clk = devm_clk_get(&pdev->dev, NULL); if (!IS_ERR(data->clk)) { - clk_prepare_enable(data->clk); - uart.port.uartclk = clk_get_rate(data->clk); + err = clk_prepare_enable(data->clk); + if (err) + dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n", + err); + else + uart.port.uartclk = clk_get_rate(data->clk); + } + + data->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); + if (!IS_ERR(data->pclk)) { + err = clk_prepare_enable(data->pclk); + if (err) { + dev_err(&pdev->dev, "could not enable apb_pclk\n"); + return err; + } } data->dma.rx_chan_id = -1; @@ -408,6 +424,9 @@ static int dw8250_remove(struct platform_device *pdev) serial8250_unregister_port(data->line); + if (!IS_ERR(data->pclk)) + clk_disable_unprepare(data->pclk); + if (!IS_ERR(data->clk)) clk_disable_unprepare(data->clk); @@ -445,6 +464,9 @@ static int dw8250_runtime_suspend(struct device *dev) if (!IS_ERR(data->clk)) clk_disable_unprepare(data->clk); + if (!IS_ERR(data->pclk)) + clk_disable_unprepare(data->pclk); + return 0; } @@ -452,6 +474,9 @@ static int dw8250_runtime_resume(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); + if (!IS_ERR(data->pclk)) + clk_prepare_enable(data->pclk); + if (!IS_ERR(data->clk)) clk_prepare_enable(data->clk); From 3bce1b70d6f2cdb83c9323c553b2336974b8516f Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:06 +0530 Subject: [PATCH 18/82] serial/arc: use uart_console_write() helper Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 643658f2b5b2..b4859598e157 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -471,14 +471,14 @@ static void arc_serial_config_port(struct uart_port *port, int flags) #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE) -static void arc_serial_poll_putchar(struct uart_port *port, unsigned char chr) +static void arc_serial_poll_putchar(struct uart_port *port, int chr) { struct arc_uart_port *uart = to_arc_port(port); while (!(UART_GET_STATUS(uart) & TXEMPTY)) cpu_relax(); - UART_SET_DATA(uart, chr); + UART_SET_DATA(uart, (unsigned char)chr); } #endif @@ -614,11 +614,6 @@ static int arc_serial_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static void arc_serial_console_putchar(struct uart_port *port, int ch) -{ - arc_serial_poll_putchar(port, (unsigned char)ch); -} - /* * Interrupts are disabled on entering */ @@ -629,7 +624,7 @@ static void arc_serial_console_write(struct console *co, const char *s, unsigned long flags; spin_lock_irqsave(&port->lock, flags); - uart_console_write(port, s, count, arc_serial_console_putchar); + uart_console_write(port, s, count, arc_serial_poll_putchar); spin_unlock_irqrestore(&port->lock, flags); } @@ -647,13 +642,8 @@ static __init void early_serial_write(struct console *con, const char *s, unsigned int n) { struct uart_port *port = &arc_uart_ports[con->index].port; - unsigned int i; - for (i = 0; i < n; i++, s++) { - if (*s == '\n') - arc_serial_poll_putchar(port, '\r'); - arc_serial_poll_putchar(port, *s); - } + uart_console_write(port, s, n, arc_serial_poll_putchar); } static struct console arc_early_serial_console __initdata = { From 12d15e6f6377fe46b1f9dc51133890a732f1ae05 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:07 +0530 Subject: [PATCH 19/82] serial/arc: Refactor by referencing to uart_port where possible The ARC UART MMIO helpers would take arc_uart_port and then reference generic uart_port->membase member. So change them to difrectly refer to uart_port and fix call sites accordingly. This removes the need for to_arc_port() converion almost eveeywhere and makes code a bit easier to read. Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 155 +++++++++++++++------------------- 1 file changed, 69 insertions(+), 86 deletions(-) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index b4859598e157..b58544de4e86 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -72,7 +72,7 @@ #define RXOERR 0x02 /* OverFlow Err: Char recv but RXFULL still set */ /* Uart bit fiddling helpers: lowest level */ -#define RBASE(uart, reg) (uart->port.membase + reg) +#define RBASE(port, reg) (port->membase + reg) #define UART_REG_SET(u, r, v) writeb((v), RBASE(u, r)) #define UART_REG_GET(u, r) readb(RBASE(u, r)) @@ -129,19 +129,15 @@ static struct uart_driver arc_uart_driver = { static void arc_serial_stop_rx(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - - UART_RX_IRQ_DISABLE(uart); + UART_RX_IRQ_DISABLE(port); } static void arc_serial_stop_tx(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - - while (!(UART_GET_STATUS(uart) & TXEMPTY)) + while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); - UART_TX_IRQ_DISABLE(uart); + UART_TX_IRQ_DISABLE(port); } /* @@ -149,10 +145,9 @@ static void arc_serial_stop_tx(struct uart_port *port) */ static unsigned int arc_serial_tx_empty(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); unsigned int stat; - stat = UART_GET_STATUS(uart); + stat = UART_GET_STATUS(port); if (stat & TXEMPTY) return TIOCSER_TEMT; @@ -166,24 +161,24 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port) * = by uart_start( ) before calling us * = tx_ist checks that too before calling */ -static void arc_serial_tx_chars(struct arc_uart_port *uart) +static void arc_serial_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &uart->port.state->xmit; + struct circ_buf *xmit = &port->state->xmit; int sent = 0; unsigned char ch; - if (unlikely(uart->port.x_char)) { - UART_SET_DATA(uart, uart->port.x_char); - uart->port.icount.tx++; - uart->port.x_char = 0; + if (unlikely(port->x_char)) { + UART_SET_DATA(port, port->x_char); + port->icount.tx++; + port->x_char = 0; sent = 1; } else if (xmit->tail != xmit->head) { /* TODO: uart_circ_empty */ ch = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uart->port.icount.tx++; - while (!(UART_GET_STATUS(uart) & TXEMPTY)) + port->icount.tx++; + while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); - UART_SET_DATA(uart, ch); + UART_SET_DATA(port, ch); sent = 1; } @@ -192,10 +187,10 @@ static void arc_serial_tx_chars(struct arc_uart_port *uart) * By Hard ISR to schedule processing in software interrupt part */ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uart->port); + uart_write_wakeup(port); if (sent) - UART_TX_IRQ_ENABLE(uart); + UART_TX_IRQ_ENABLE(port); } /* @@ -204,12 +199,10 @@ static void arc_serial_tx_chars(struct arc_uart_port *uart) */ static void arc_serial_start_tx(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - - arc_serial_tx_chars(uart); + arc_serial_tx_chars(port); } -static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status) +static void arc_serial_rx_chars(struct uart_port *port, unsigned int status) { unsigned int ch, flg = 0; @@ -229,15 +222,15 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status) */ if (unlikely(status & (RXOERR | RXFERR))) { if (status & RXOERR) { - uart->port.icount.overrun++; + port->icount.overrun++; flg = TTY_OVERRUN; - UART_CLR_STATUS(uart, RXOERR); + UART_CLR_STATUS(port, RXOERR); } if (status & RXFERR) { - uart->port.icount.frame++; + port->icount.frame++; flg = TTY_FRAME; - UART_CLR_STATUS(uart, RXFERR); + UART_CLR_STATUS(port, RXFERR); } } else flg = TTY_NORMAL; @@ -245,16 +238,16 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status) if (status & RXEMPTY) continue; - ch = UART_GET_DATA(uart); - uart->port.icount.rx++; + ch = UART_GET_DATA(port); + port->icount.rx++; - if (!(uart_handle_sysrq_char(&uart->port, ch))) - uart_insert_char(&uart->port, status, RXOERR, ch, flg); + if (!(uart_handle_sysrq_char(port, ch))) + uart_insert_char(port, status, RXOERR, ch, flg); - spin_unlock(&uart->port.lock); - tty_flip_buffer_push(&uart->port.state->port); - spin_lock(&uart->port.lock); - } while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)); + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); + } while (!((status = UART_GET_STATUS(port)) & RXEMPTY)); } /* @@ -287,10 +280,10 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status) static irqreturn_t arc_serial_isr(int irq, void *dev_id) { - struct arc_uart_port *uart = dev_id; + struct uart_port *port = dev_id; unsigned int status; - status = UART_GET_STATUS(uart); + status = UART_GET_STATUS(port); /* * Single IRQ for both Rx (data available) Tx (room available) Interrupt @@ -300,9 +293,9 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id) if (status & RXIENB) { /* already in ISR, no need of xx_irqsave */ - spin_lock(&uart->port.lock); - arc_serial_rx_chars(uart, status); - spin_unlock(&uart->port.lock); + spin_lock(&port->lock); + arc_serial_rx_chars(port, status); + spin_unlock(&port->lock); } if ((status & TXIENB) && (status & TXEMPTY)) { @@ -310,14 +303,14 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id) /* Unconditionally disable further Tx-Interrupts. * will be enabled by tx_chars() if needed. */ - UART_TX_IRQ_DISABLE(uart); + UART_TX_IRQ_DISABLE(port); - spin_lock(&uart->port.lock); + spin_lock(&port->lock); - if (!uart_tx_stopped(&uart->port)) - arc_serial_tx_chars(uart); + if (!uart_tx_stopped(port)) + arc_serial_tx_chars(port); - spin_unlock(&uart->port.lock); + spin_unlock(&port->lock); } return IRQ_HANDLED; @@ -347,18 +340,15 @@ static void arc_serial_break_ctl(struct uart_port *port, int break_state) static int arc_serial_startup(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - /* Before we hook up the ISR, Disable all UART Interrupts */ - UART_ALL_IRQ_DISABLE(uart); + UART_ALL_IRQ_DISABLE(port); - if (request_irq(uart->port.irq, arc_serial_isr, 0, "arc uart rx-tx", - uart)) { - dev_warn(uart->port.dev, "Unable to attach ARC UART intr\n"); + if (request_irq(port->irq, arc_serial_isr, 0, "arc uart rx-tx", port)) { + dev_warn(port->dev, "Unable to attach ARC UART intr\n"); return -EBUSY; } - UART_RX_IRQ_ENABLE(uart); /* Only Rx IRQ enabled to begin with */ + UART_RX_IRQ_ENABLE(port); /* Only Rx IRQ enabled to begin with */ return 0; } @@ -366,8 +356,7 @@ static int arc_serial_startup(struct uart_port *port) /* This is not really needed */ static void arc_serial_shutdown(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - free_irq(uart->port.irq, uart); + free_irq(port->irq, port); } static void @@ -404,12 +393,12 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new, spin_lock_irqsave(&port->lock, flags); - UART_ALL_IRQ_DISABLE(uart); + UART_ALL_IRQ_DISABLE(port); - UART_SET_BAUDL(uart, uartl); - UART_SET_BAUDH(uart, uarth); + UART_SET_BAUDL(port, uartl); + UART_SET_BAUDH(port, uarth); - UART_RX_IRQ_ENABLE(uart); + UART_RX_IRQ_ENABLE(port); /* * UART doesn't support Parity/Hardware Flow Control; @@ -432,9 +421,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new, static const char *arc_serial_type(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); - - return uart->port.type == PORT_ARC ? DRIVER_NAME : NULL; + return port->type == PORT_ARC ? DRIVER_NAME : NULL; } static void arc_serial_release_port(struct uart_port *port) @@ -463,35 +450,30 @@ arc_serial_verify_port(struct uart_port *port, struct serial_struct *ser) */ static void arc_serial_config_port(struct uart_port *port, int flags) { - struct arc_uart_port *uart = to_arc_port(port); - if (flags & UART_CONFIG_TYPE) - uart->port.type = PORT_ARC; + port->type = PORT_ARC; } #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE) static void arc_serial_poll_putchar(struct uart_port *port, int chr) { - struct arc_uart_port *uart = to_arc_port(port); - - while (!(UART_GET_STATUS(uart) & TXEMPTY)) + while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); - UART_SET_DATA(uart, (unsigned char)chr); + UART_SET_DATA(port, (unsigned char)chr); } #endif #ifdef CONFIG_CONSOLE_POLL static int arc_serial_poll_getchar(struct uart_port *port) { - struct arc_uart_port *uart = to_arc_port(port); unsigned char chr; - while (!(UART_GET_STATUS(uart) & RXEMPTY)) + while (!(UART_GET_STATUS(port) & RXEMPTY)) cpu_relax(); - chr = UART_GET_DATA(uart); + chr = UART_GET_DATA(port); return chr; } #endif @@ -524,6 +506,7 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id) struct resource *res, *res2; unsigned long *plat_data; struct arc_uart_port *uart = &arc_uart_ports[dev_id]; + struct uart_port *port = &uart->port; plat_data = dev_get_platdata(&pdev->dev); if (!plat_data) @@ -532,7 +515,7 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id) uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */ if (is_early_platform_device(pdev)) { - uart->port.uartclk = plat_data[1]; + port->uartclk = plat_data[1]; uart->baud = plat_data[2]; } else { struct device_node *np = pdev->dev.of_node; @@ -542,7 +525,7 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id) dev_err(&pdev->dev, "clock-frequency property NOTset\n"); return -EINVAL; } - uart->port.uartclk = val; + port->uartclk = val; if (of_property_read_u32(np, "current-speed", &val)) { dev_err(&pdev->dev, "current-speed property NOT set\n"); @@ -559,26 +542,26 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id) if (!res2) return -ENODEV; - uart->port.mapbase = res->start; - uart->port.membase = ioremap_nocache(res->start, resource_size(res)); - if (!uart->port.membase) + port->mapbase = res->start; + port->membase = ioremap_nocache(res->start, resource_size(res)); + if (!port->membase) /* No point of dev_err since UART itself is hosed here */ return -ENXIO; - uart->port.irq = res2->start; - uart->port.dev = &pdev->dev; - uart->port.iotype = UPIO_MEM; - uart->port.flags = UPF_BOOT_AUTOCONF; - uart->port.line = dev_id; - uart->port.ops = &arc_serial_pops; + port->irq = res2->start; + port->dev = &pdev->dev; + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->line = dev_id; + port->ops = &arc_serial_pops; - uart->port.fifosize = ARC_UART_TX_FIFO_SIZE; + port->fifosize = ARC_UART_TX_FIFO_SIZE; /* * uart_insert_char( ) uses it in decideding whether to ignore a * char or not. Explicitly setting it here, removes the subtelty */ - uart->port.ignore_status_mask = 0; + port->ignore_status_mask = 0; return 0; } From 5a56d59e853b3dcd97e9497c1c7d3834b24f0664 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:08 +0530 Subject: [PATCH 20/82] serial/arc: Remove the workaround for legacy ISS Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index b58544de4e86..ea954c3be18b 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -102,7 +102,6 @@ struct arc_uart_port { struct uart_port port; unsigned long baud; - int is_emulated; /* H/w vs. Instruction Set Simulator */ }; #define to_arc_port(uport) container_of(uport, struct arc_uart_port, port) @@ -380,17 +379,6 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new, uartl = hw_val & 0xFF; uarth = (hw_val >> 8) & 0xFF; - /* - * UART ISS(Instruction Set simulator) emulation has a subtle bug: - * A existing value of Baudh = 0 is used as a indication to startup - * it's internal state machine. - * Thus if baudh is set to 0, 2 times, it chokes. - * This happens with BAUD=115200 and the formaula above - * Until that is fixed, when running on ISS, we will set baudh to !0 - */ - if (uart->is_emulated) - uarth = 1; - spin_lock_irqsave(&port->lock, flags); UART_ALL_IRQ_DISABLE(port); @@ -512,8 +500,6 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id) if (!plat_data) return -ENODEV; - uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */ - if (is_early_platform_device(pdev)) { port->uartclk = plat_data[1]; uart->baud = plat_data[2]; From 27cfe4ec17d85c2a9e7f26804d1652ad3fabf19e Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:09 +0530 Subject: [PATCH 21/82] serial/arc: Use generic earlycon infrastructure With this change both earlyprintk and earlycon coexist We switch over to latter in next patch Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/arc_uart.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 7039238b134f..7f12a005c6cb 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1472,6 +1472,7 @@ config SERIAL_ARC_CONSOLE bool "Console on ARC UART" depends on SERIAL_ARC=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Enable system Console on ARC UART diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index ea954c3be18b..41d2e351c06d 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -638,6 +638,36 @@ static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev) register_console(&arc_early_serial_console); return 0; } + +static __init void arc_early_serial_write(struct console *con, const char *s, + unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, arc_serial_poll_putchar); +} + +static int __init arc_early_console_setup(struct earlycon_device *dev, + const char *opt) +{ + struct uart_port *port = &dev->port; + unsigned int l, h, hw_val; + + if (!dev->port.membase) + return -ENODEV; + + hw_val = port->uartclk / (dev->baud * 4) - 1; + l = hw_val & 0xFF; + h = (hw_val >> 8) & 0xFF; + + UART_SET_BAUDL(port, l); + UART_SET_BAUDH(port, h); + + dev->con->write = arc_early_serial_write; + return 0; +} +EARLYCON_DECLARE(arc_uart, arc_early_console_setup); + #endif /* CONFIG_SERIAL_ARC_CONSOLE */ static int arc_serial_probe(struct platform_device *pdev) From 2e6fb7cbd0632d4230d4219ee9eb610f975d6669 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:10 +0530 Subject: [PATCH 22/82] serial/arc: remove earlyprintk support and switch to earlycon Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- arch/arc/boot/dts/angel4.dts | 2 +- drivers/tty/serial/arc_uart.c | 87 +++++------------------------------ 2 files changed, 13 insertions(+), 76 deletions(-) diff --git a/arch/arc/boot/dts/angel4.dts b/arch/arc/boot/dts/angel4.dts index 5bb2fdaca02f..6b57475967a6 100644 --- a/arch/arc/boot/dts/angel4.dts +++ b/arch/arc/boot/dts/angel4.dts @@ -17,7 +17,7 @@ / { interrupt-parent = <&intc>; chosen { - bootargs = "console=ttyARC0,115200n8 earlyprintk=ttyARC0"; + bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8"; }; aliases { diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 41d2e351c06d..94d345bfd08d 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -492,33 +492,23 @@ static int arc_uart_init_one(struct platform_device *pdev, int dev_id) { struct resource *res, *res2; - unsigned long *plat_data; struct arc_uart_port *uart = &arc_uart_ports[dev_id]; struct uart_port *port = &uart->port; - plat_data = dev_get_platdata(&pdev->dev); - if (!plat_data) - return -ENODEV; + struct device_node *np = pdev->dev.of_node; + u32 val; - if (is_early_platform_device(pdev)) { - port->uartclk = plat_data[1]; - uart->baud = plat_data[2]; - } else { - struct device_node *np = pdev->dev.of_node; - u32 val; - - if (of_property_read_u32(np, "clock-frequency", &val)) { - dev_err(&pdev->dev, "clock-frequency property NOTset\n"); - return -EINVAL; - } - port->uartclk = val; - - if (of_property_read_u32(np, "current-speed", &val)) { - dev_err(&pdev->dev, "current-speed property NOT set\n"); - return -EINVAL; - } - uart->baud = val; + if (of_property_read_u32(np, "clock-frequency", &val)) { + dev_err(&pdev->dev, "clock-frequency property NOTset\n"); + return -EINVAL; } + port->uartclk = val; + + if (of_property_read_u32(np, "current-speed", &val)) { + dev_err(&pdev->dev, "current-speed property NOT set\n"); + return -EINVAL; + } + uart->baud = val; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -607,38 +597,6 @@ static struct console arc_console = { .data = &arc_uart_driver }; -static __init void early_serial_write(struct console *con, const char *s, - unsigned int n) -{ - struct uart_port *port = &arc_uart_ports[con->index].port; - - uart_console_write(port, s, n, arc_serial_poll_putchar); -} - -static struct console arc_early_serial_console __initdata = { - .name = "early_ARCuart", - .write = early_serial_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1 -}; - -static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev) -{ - int dev_id = pdev->id < 0 ? 0 : pdev->id; - int rc; - - arc_early_serial_console.index = dev_id; - - rc = arc_uart_init_one(pdev, dev_id); - if (rc) - panic("early console init failed\n"); - - arc_serial_console_setup(&arc_early_serial_console, NULL); - - register_console(&arc_early_serial_console); - return 0; -} - static __init void arc_early_serial_write(struct console *con, const char *s, unsigned int n) { @@ -713,27 +671,6 @@ static struct platform_driver arc_platform_driver = { }, }; -#ifdef CONFIG_SERIAL_ARC_CONSOLE - -static struct platform_driver early_arc_platform_driver __initdata = { - .probe = arc_serial_probe_earlyprintk, - .remove = arc_serial_remove, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; -/* - * Register an early platform driver of "earlyprintk" class. - * ARCH platform code installs the driver and probes the early devices - * The installation could rely on user specifying earlyprintk=xyx in cmd line - * or it could be done independently, for all "earlyprintk" class drivers. - * [see arch/arc/plat-arcfpga/platform.c] - */ -early_platform_init("earlyprintk", &early_arc_platform_driver); - -#endif /* CONFIG_SERIAL_ARC_CONSOLE */ - static int __init arc_serial_init(void) { int ret; From 91f1b62a9b2b8d334b64d3029f4b0dcccf56bc1e Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:11 +0530 Subject: [PATCH 23/82] serial/arc: remove last remanants of platform data Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 94d345bfd08d..68433adea35b 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -37,8 +37,8 @@ #include #include #include -#include -#include +#include +#include /************************************* * ARC UART Hardware Specs @@ -491,11 +491,9 @@ static struct uart_ops arc_serial_pops = { static int arc_uart_init_one(struct platform_device *pdev, int dev_id) { - struct resource *res, *res2; + struct device_node *np = pdev->dev.of_node; struct arc_uart_port *uart = &arc_uart_ports[dev_id]; struct uart_port *port = &uart->port; - - struct device_node *np = pdev->dev.of_node; u32 val; if (of_property_read_u32(np, "clock-frequency", &val)) { @@ -510,21 +508,13 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id) } uart->baud = val; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; - - port->mapbase = res->start; - port->membase = ioremap_nocache(res->start, resource_size(res)); + port->membase = of_iomap(np, 0); if (!port->membase) /* No point of dev_err since UART itself is hosed here */ return -ENXIO; - port->irq = res2->start; + port->irq = irq_of_parse_and_map(np, 0); + port->dev = &pdev->dev; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; From 8dbe1d5e09a7faec8d22cadcc1011acab8fa6e2a Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:12 +0530 Subject: [PATCH 24/82] serial/arc: inline the probe helper Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 90 ++++++++++++++++------------------- 1 file changed, 40 insertions(+), 50 deletions(-) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 68433adea35b..3b5285373658 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -488,50 +488,6 @@ static struct uart_ops arc_serial_pops = { #endif }; -static int -arc_uart_init_one(struct platform_device *pdev, int dev_id) -{ - struct device_node *np = pdev->dev.of_node; - struct arc_uart_port *uart = &arc_uart_ports[dev_id]; - struct uart_port *port = &uart->port; - u32 val; - - if (of_property_read_u32(np, "clock-frequency", &val)) { - dev_err(&pdev->dev, "clock-frequency property NOTset\n"); - return -EINVAL; - } - port->uartclk = val; - - if (of_property_read_u32(np, "current-speed", &val)) { - dev_err(&pdev->dev, "current-speed property NOT set\n"); - return -EINVAL; - } - uart->baud = val; - - port->membase = of_iomap(np, 0); - if (!port->membase) - /* No point of dev_err since UART itself is hosed here */ - return -ENXIO; - - port->irq = irq_of_parse_and_map(np, 0); - - port->dev = &pdev->dev; - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF; - port->line = dev_id; - port->ops = &arc_serial_pops; - - port->fifosize = ARC_UART_TX_FIFO_SIZE; - - /* - * uart_insert_char( ) uses it in decideding whether to ignore a - * char or not. Explicitly setting it here, removes the subtelty - */ - port->ignore_status_mask = 0; - - return 0; -} - #ifdef CONFIG_SERIAL_ARC_CONSOLE static int arc_serial_console_setup(struct console *co, char *options) @@ -620,8 +576,11 @@ EARLYCON_DECLARE(arc_uart, arc_early_console_setup); static int arc_serial_probe(struct platform_device *pdev) { - int rc, dev_id; struct device_node *np = pdev->dev.of_node; + struct arc_uart_port *uart; + struct uart_port *port; + int dev_id; + u32 val; /* no device tree device */ if (!np) @@ -631,12 +590,43 @@ static int arc_serial_probe(struct platform_device *pdev) if (dev_id < 0) dev_id = 0; - rc = arc_uart_init_one(pdev, dev_id); - if (rc) - return rc; + uart = &arc_uart_ports[dev_id]; + port = &uart->port; - rc = uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port); - return rc; + if (of_property_read_u32(np, "clock-frequency", &val)) { + dev_err(&pdev->dev, "clock-frequency property NOTset\n"); + return -EINVAL; + } + port->uartclk = val; + + if (of_property_read_u32(np, "current-speed", &val)) { + dev_err(&pdev->dev, "current-speed property NOT set\n"); + return -EINVAL; + } + uart->baud = val; + + port->membase = of_iomap(np, 0); + if (!port->membase) + /* No point of dev_err since UART itself is hosed here */ + return -ENXIO; + + port->irq = irq_of_parse_and_map(np, 0); + + port->dev = &pdev->dev; + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->line = dev_id; + port->ops = &arc_serial_pops; + + port->fifosize = ARC_UART_TX_FIFO_SIZE; + + /* + * uart_insert_char( ) uses it in decideding whether to ignore a + * char or not. Explicitly setting it here, removes the subtelty + */ + port->ignore_status_mask = 0; + + return uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port); } static int arc_serial_remove(struct platform_device *pdev) From 1b9bff759b03f79173035236ea6f5ff44d9aa866 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:13 +0530 Subject: [PATCH 25/82] ARC: [arcfpga] RIP early uart platform device stuff With ARC uart driver switching to generic earlycon, we no longer need this ugliness. You won't be missed. Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- arch/arc/plat-arcfpga/Kconfig | 7 --- arch/arc/plat-arcfpga/platform.c | 97 +------------------------------- 2 files changed, 2 insertions(+), 102 deletions(-) diff --git a/arch/arc/plat-arcfpga/Kconfig b/arch/arc/plat-arcfpga/Kconfig index e27bb5cc3c1e..b9f34cf55acf 100644 --- a/arch/arc/plat-arcfpga/Kconfig +++ b/arch/arc/plat-arcfpga/Kconfig @@ -41,11 +41,4 @@ config ISS_SMP_EXTN -XTL (To enable CPU start/stop/set-PC for another CPU) It doesn't provide coherent Caches and/or Atomic Ops (LLOCK/SCOND) -config ARC_SERIAL_BAUD - int "UART Baud rate" - default "115200" - depends on SERIAL_ARC || SERIAL_ARC_CONSOLE - help - Baud rate for the ARC UART - endif diff --git a/arch/arc/plat-arcfpga/platform.c b/arch/arc/plat-arcfpga/platform.c index 61c7e5997387..b8d0d456627f 100644 --- a/arch/arc/plat-arcfpga/platform.c +++ b/arch/arc/plat-arcfpga/platform.c @@ -22,115 +22,22 @@ #include #include -/*----------------------- Platform Devices -----------------------------*/ - -#if IS_ENABLED(CONFIG_SERIAL_ARC) -static unsigned long arc_uart_info[] = { - 0, /* uart->is_emulated (runtime @running_on_hw) */ - 0, /* uart->port.uartclk */ - 0, /* uart->baud */ - 0 -}; - -#if defined(CONFIG_SERIAL_ARC_CONSOLE) -/* - * static platform data - but only for early serial - * TBD: derive this from a special DT node - */ -static struct resource arc_uart0_res[] = { - { - .start = UART0_BASE, - .end = UART0_BASE + 0xFF, - .flags = IORESOURCE_MEM, - }, - { - .start = UART0_IRQ, - .end = UART0_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device arc_uart0_dev = { - .name = "arc-uart", - .id = 0, - .num_resources = ARRAY_SIZE(arc_uart0_res), - .resource = arc_uart0_res, - .dev = { - .platform_data = &arc_uart_info, - }, -}; - -static struct platform_device *fpga_early_devs[] __initdata = { - &arc_uart0_dev, -}; -#endif /* CONFIG_SERIAL_ARC_CONSOLE */ - -static void arc_fpga_serial_init(void) -{ - /* To let driver workaround ISS bug: baudh Reg can't be set to 0 */ - arc_uart_info[0] = !running_on_hw; - - arc_uart_info[1] = arc_get_core_freq(); - - arc_uart_info[2] = CONFIG_ARC_SERIAL_BAUD; - -#if defined(CONFIG_SERIAL_ARC_CONSOLE) - early_platform_add_devices(fpga_early_devs, - ARRAY_SIZE(fpga_early_devs)); - - /* - * ARC console driver registers (build time) as an early platform driver - * of class "earlyprintk". However it needs explicit cmdline toggle - * "earlyprintk=ttyARC0" to be successfuly runtime registered. - * Otherwise the early probe below fails to find the driver - */ - early_platform_driver_probe("earlyprintk", 1, 0); - - /* - * This is to make sure that arc uart would be preferred console - * despite one/more of following: - * -command line lacked "console=ttyARC0" or - * -CONFIG_VT_CONSOLE was enabled (for no reason whatsoever) - * Note that this needs to be done after above early console is reg, - * otherwise the early console never gets a chance to run. - */ - add_preferred_console("ttyARC", 0, "115200"); -#endif /* CONFIG_SERIAL_ARC_CONSOLE */ -} -#else /* !IS_ENABLED(CONFIG_SERIAL_ARC) */ -static void arc_fpga_serial_init(void) -{ -} -#endif - static void __init plat_fpga_early_init(void) { pr_info("[plat-arcfpga]: registering early dev resources\n"); - arc_fpga_serial_init(); - #ifdef CONFIG_ISS_SMP_EXTN iss_model_init_early_smp(); #endif } -static struct of_dev_auxdata plat_auxdata_lookup[] __initdata = { -#if IS_ENABLED(CONFIG_SERIAL_ARC) - OF_DEV_AUXDATA("snps,arc-uart", UART0_BASE, "arc-uart", arc_uart_info), -#endif - {} -}; - static void __init plat_fpga_populate_dev(void) { - pr_info("[plat-arcfpga]: registering device resources\n"); - /* * Traverses flattened DeviceTree - registering platform devices - * complete with their resources + * (if any) complete with their resources */ - of_platform_populate(NULL, of_default_bus_match_table, - plat_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } /*----------------------- Machine Descriptions ------------------------------ From 8c6abf7a9e5d0f4a27140cf13220a28e0f5c829c Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:14 +0530 Subject: [PATCH 26/82] serial/arc: Enable DT based earlycon This allows a param less earlycon to pick up the earlyconsole from chosen/stdout-path Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 3b5285373658..3a504fb9c9e8 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -571,6 +571,7 @@ static int __init arc_early_console_setup(struct earlycon_device *dev, return 0; } EARLYCON_DECLARE(arc_uart, arc_early_console_setup); +OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup); #endif /* CONFIG_SERIAL_ARC_CONSOLE */ From 9da433c0a0b5f71ac92dc9dca778295649675f08 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 24 Jun 2014 13:55:15 +0530 Subject: [PATCH 27/82] ARC: [arcfpga] stdout-path now suffices for earlycon/console With recent improvements to serial/of core from Grant and Rob, stdout-path alone suffices for setting up earlycon/console. arc_uart driver is already equipped to handle that, switch the DT now. Signed-off-by: Vineet Gupta Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- arch/arc/boot/dts/angel4.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arc/boot/dts/angel4.dts b/arch/arc/boot/dts/angel4.dts index 6b57475967a6..298a46daa633 100644 --- a/arch/arc/boot/dts/angel4.dts +++ b/arch/arc/boot/dts/angel4.dts @@ -17,7 +17,8 @@ / { interrupt-parent = <&intc>; chosen { - bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8"; + bootargs = "earlycon"; + stdout-path = &arcuart0; }; aliases { From 2ee881b74e1fa96bfe0c7d2be11f6de69bc145e9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Feb 2014 16:14:20 +0100 Subject: [PATCH 28/82] serial: pxa: fix build with !SERIAL_PXA_CONSOLE When CONFIG_SERIAL_PXA_CONSOLE is disabled, the serial_pxa_get_poll_char and serial_pxa_put_poll_char functions are not defined, and we can't reference them. Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index c638c53cd2b6..21b7d8b86493 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -778,7 +778,7 @@ static struct uart_ops serial_pxa_pops = { .request_port = serial_pxa_request_port, .config_port = serial_pxa_config_port, .verify_port = serial_pxa_verify_port, -#ifdef CONFIG_CONSOLE_POLL +#if defined(CONFIG_CONSOLE_POLL) && defined(CONFIG_SERIAL_PXA_CONSOLE) .poll_get_char = serial_pxa_get_poll_char, .poll_put_char = serial_pxa_put_poll_char, #endif From 080029b149258b9ccb05f26ee5f5d18e359bce2d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 Jun 2014 22:54:27 +0200 Subject: [PATCH 29/82] serial: lpc32xx uart module can't do console Every uart driver that provides a console driver needs to be built-in for the console code to work, we get a build error for modular console drivers. This changes the SERIAL_HS_LPC32XX_CONSOLE symbol to depend on the SERIAL_HS_LPC32XX driver being built-in, just like we do for all the other uart drivers. Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 7f12a005c6cb..26cec64dadd7 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -773,7 +773,7 @@ config SERIAL_HS_LPC32XX config SERIAL_HS_LPC32XX_CONSOLE bool "Enable LPC32XX high speed UART serial console" - depends on SERIAL_HS_LPC32XX + depends on SERIAL_HS_LPC32XX=y select SERIAL_CORE_CONSOLE help If you would like to be able to use one of the high speed serial From 5e3dbfca3b14a4a2950255c1628cd53b384d963e Mon Sep 17 00:00:00 2001 From: Pradeep Goudagunta Date: Fri, 6 Jun 2014 16:48:08 +0530 Subject: [PATCH 30/82] serial: tegra: update tx_circular buffer only when TX_DMA is in progress When channel is require to stop transmit then update the Tx circular buffer only when DMA based transfer is in progress. If there is no DMA based transfer then no need to update the Tx buffer. Signed-off-by: Pradeep Goudagunta Signed-off-by: Laxman Dewangan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial-tegra.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index d5c2a287b7e7..117d8d1382f9 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -482,6 +482,9 @@ static void tegra_uart_stop_tx(struct uart_port *u) struct dma_tx_state state; int count; + if (tup->tx_in_progress != TEGRA_UART_TX_DMA) + return; + dmaengine_terminate_all(tup->tx_dma_chan); dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); count = tup->tx_bytes_requested - state.residue; From b31245b9420731cc62bb1eea0a2240b3e90a2e78 Mon Sep 17 00:00:00 2001 From: Pradeep Goudagunta Date: Fri, 6 Jun 2014 16:48:09 +0530 Subject: [PATCH 31/82] serial: tegra: ack the rx dma desc after transfer terminated The Rx dma descriptor allocated without the DMA_ACK flags so that once after tarnsfer done or terminated, client can ack the descriptor to free it for later use. If the Rx DMA is terminated for some reason then rx-dma descriptor is not getting acked which causes the memory leak and list of usage desc to grow continuously. Hence, acknowledge the rx-dma descriptor once transfer is terminated to avoid memory leak and desc list to grow. Signed-off-by: Laxman Dewangan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial-tegra.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 117d8d1382f9..53d7c31ce098 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -602,6 +602,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup, dmaengine_terminate_all(tup->rx_dma_chan); dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + async_tx_ack(tup->rx_dma_desc); count = tup->rx_bytes_requested - state.residue; /* If we are here, DMA is stopped */ From ae84db9661cafc63d179e1d985a2c5b841ff0ac4 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 9 Jul 2014 09:21:14 -0400 Subject: [PATCH 32/82] serial: core: Preserve termios c_cflag for console resume When a tty is opened for the serial console, the termios c_cflag settings are inherited from the console line settings. However, if the tty is subsequently closed, the termios settings are lost. This results in a garbled console if the console is later suspended and resumed. Preserve the termios c_cflag for the serial console when the tty is shutdown; this reflects the most recent line settings. Fixes: Bugzilla #69751, 'serial console does not wake from S3' Reported-by: Valerio Vanni Acked-by: Alan Cox Signed-off-by: Peter Hurley Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a0e2f9d63b9d..127ac6c8fd40 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -243,6 +243,9 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Turn off DTR and RTS early. */ + if (uart_console(uport) && tty) + uport->cons->cflag = tty->termios.c_cflag; + if (!tty || (tty->termios.c_cflag & HUPCL)) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); From 90abef91c5974d3d4845d64fd75a319fb20f6e6b Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 2 Jul 2014 18:02:56 +0200 Subject: [PATCH 33/82] serial: fsl_lpuart: move DMA RX timeout calculation The DMA RX timeout calculation is done based on FIFO buffer size and port timeout when setting up DMA. However, both variables are not necessarily initialized at DMA initialization time, which can lead to a division by zero. Move the timeout calculation to set_termios where both variables are initialized. Signed-off-by: Stefan Agner Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index c5ad567cab8d..5fde6da6ba20 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -720,13 +720,6 @@ static int lpuart_dma_rx_request(struct uart_port *port) sport->dma_rx_buf_bus = dma_bus; sport->dma_rx_in_progress = 0; - sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) * - FSL_UART_RX_DMA_BUFFER_SIZE * 3 / - sport->rxfifo_size / 2; - - if (sport->dma_rx_timeout < msecs_to_jiffies(20)) - sport->dma_rx_timeout = msecs_to_jiffies(20); - return 0; } @@ -918,6 +911,17 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); + if (sport->lpuart_dma_use) { + /* Calculate delay for 1.5 DMA buffers */ + sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) * + FSL_UART_RX_DMA_BUFFER_SIZE * 3 / + sport->rxfifo_size / 2; + dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", + sport->dma_rx_timeout * 1000 / HZ, sport->port.timeout); + if (sport->dma_rx_timeout < msecs_to_jiffies(20)) + sport->dma_rx_timeout = msecs_to_jiffies(20); + } + /* wait transmit engin complete */ while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC)) barrier(); From ed9891bf093638fad29f89c10b536550d29b129d Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 2 Jul 2014 18:02:57 +0200 Subject: [PATCH 34/82] serial: fsl_lpuart: calculate DMA burst The DMA burst size must match the transmit FIFO depth in order to make sure all character are transmitted. This patch calculates DMA burst size by using FIFO depth rather than use the hardcoded 16 bytes. This is required since some UARTs (e.g. UART2 on Vybrid) have a FIFO depth of 8 bytes. Signed-off-by: Stefan Agner Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 5fde6da6ba20..acd3617677e8 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -117,8 +117,6 @@ #define UARTSFIFO_TXOF 0x02 #define UARTSFIFO_RXUF 0x01 -#define DMA_MAXBURST 16 -#define DMA_MAXBURST_MASK (DMA_MAXBURST - 1) #define FSL_UART_RX_DMA_BUFFER_SIZE 64 #define DRIVER_NAME "fsl-lpuart" @@ -236,7 +234,7 @@ static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count) dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus, UART_XMIT_SIZE, DMA_TO_DEVICE); - sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK); + sport->dma_tx_bytes = count & ~(sport->txfifo_size - 1); tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail; sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan, tx_bus_addr, sport->dma_tx_bytes, @@ -265,7 +263,7 @@ static void lpuart_prepare_tx(struct lpuart_port *sport) if (!count) return; - if (count < DMA_MAXBURST) + if (count < sport->txfifo_size) writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS, sport->port.membase + UARTCR5); else { @@ -595,15 +593,7 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) UARTCR2_RIE | UARTCR2_RE); writeb(cr2, sport->port.membase + UARTCR2); - /* determine FIFO size and enable FIFO mode */ val = readb(sport->port.membase + UARTPFIFO); - - sport->txfifo_size = 0x1 << (((val >> UARTPFIFO_TXSIZE_OFF) & - UARTPFIFO_FIFOSIZE_MASK) + 1); - - sport->rxfifo_size = 0x1 << (((val >> UARTPFIFO_RXSIZE_OFF) & - UARTPFIFO_FIFOSIZE_MASK) + 1); - writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE, sport->port.membase + UARTPFIFO); @@ -648,7 +638,7 @@ static int lpuart_dma_tx_request(struct uart_port *port) dma_buf = sport->port.state->xmit.buf; dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma_tx_sconfig.dst_maxburst = DMA_MAXBURST; + dma_tx_sconfig.dst_maxburst = sport->txfifo_size; dma_tx_sconfig.direction = DMA_MEM_TO_DEV; ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig); @@ -761,7 +751,16 @@ static int lpuart_startup(struct uart_port *port) unsigned long flags; unsigned char temp; - /*whether use dma support by dma request results*/ + /* determine FIFO size and enable FIFO mode */ + temp = readb(sport->port.membase + UARTPFIFO); + + sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK) + 1); + + sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK) + 1); + + /* Whether use dma support by dma request results */ if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) { sport->lpuart_dma_use = false; } else { From ed617e44234ee03a60edbf0809f696f0b9cf1b90 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:16:58 -0400 Subject: [PATCH 35/82] tty: Document locking for tty driver methods The tty core calls the tty driver's open, close and hangup methods holding the tty lock. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/linux/tty_driver.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 756a60989294..e48c608a8fa8 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -35,14 +35,14 @@ * This routine is mandatory; if this routine is not filled in, * the attempted open will fail with ENODEV. * - * Required method. - * + * Required method. Called with tty lock held. + * * void (*close)(struct tty_struct * tty, struct file * filp); * * This routine is called when a particular tty device is closed. * Note: called even if the corresponding open() failed. * - * Required method. + * Required method. Called with tty lock held. * * void (*shutdown)(struct tty_struct * tty); * @@ -172,6 +172,8 @@ * * Optional: * + * Called with tty lock held. + * * int (*break_ctl)(struct tty_struct *tty, int state); * * This optional routine requests the tty driver to turn on or From 0733db91d06a555b3f85f0b4c958c8949ed22e1d Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:16:59 -0400 Subject: [PATCH 36/82] tty: Document locking for tty_port_close{,start,end}() The tty lock is held when the tty driver's .close method is called (from the two lone call-sites of tty_release() and __tty_hangup()). The call-tree audit[1] of tty_port_close(), tty_port_close_start, and tty_port_close_end() is a closed graph of the callers of these 3 functions; ie., all callers originate from only tty_release() or __tty_hangup(). Of these callers, none drop the tty lock. Also, document tty_port_close_start() may drop and reacquire the tty lock in tty_wait_until_sent_from_close(), which means the tty or tty_port may have changed state (but not reopened or hung up). [1] Call-tree audit of tty_port_close, tty_port_close_start, and tty_port_close_end() tty_release() tty->ops->close() --+ | __tty_hangup() | tty->ops->close() --+ | +- rp_close():drivers/tty/rocket.c -------------------+ +- uart_close():drivers/tty/serial/serial_core.c -----+ | +- tty_port_close_start() | | +- close():drivers/tty/synclinkmp.c ------------------+ +- rs_close():drivers/tty/amiserial.c ----------------+ +- gsmtty_close():drivers/tty/n_gsm.c ----------------+ +- mxser_close():drivers/tty/mxser.c -----------------+ +- close():drivers/tty/synclink_gt.c -----------------+ +- mgsl_close():drivers/tty/synclink.c ---------------+ +- isdn_tty_close():drivers/isdn/i4l/isdn_tty.c ------+ +- mgslpc_close():drivers/char/pcmcia/synclink_cs.c --+ +- ircomm_tty_close():net/irda/ircomm/ircomm_tty.c ---+ | | rs_close():arch/ia64/hp/sim/simserial.c | *line_close():arch/um/drivers/line.c | gdm_tty_close():drivers/staging/gdm724x/gdm_tty.c fwtty_close():drivers/staging/fwserial/fwserial.c acm_tty_close():drivers/usb/class/cdc-acm.c serial_close():drivers/usb/serial/usb-serial.c pti_tty_driver_close():drivers/misc/pti.c ipoctal_close():drivers/ipack/devices/ipoctal.c cy_close():drivers/tty/cyclades.c isicom_close():drivers/tty/isicom.c dashtty_close():drivers/tty/metag_da.c moxa_close():drivers/tty/moxa.c goldfish_tty_close():drivers/tty/goldfish.c ehv_bc_tty_close():drivers/tty/ehv_bytechan.c kgdb_nmi_tty_close():drivers/tty/serial/kgdb_nmi.c ifx_spi_close():drivers/tty/serial/ifx6x60.c smd_tty_close():drivers/tty/serial/msm_smd_tty.c ntty_close():drivers/tty/nozomi.c capinc_tty_close():drivers/isdn/capi/capi.c tpk_close():drivers/char/ttyprintk.c sdio_uart_close():drivers/mmc/card/sdio_uart.c | rfcomm_tty_close():net/bluetooth/rfcomm/tty.c | | | +- tty_port_close():drivers/tty/tty_port.c -----------+ | +- tty_port_close_start() +- tty_port_close_end() * line_close() is the .close method for 2 um drivers, declared in ./arch/um/drivers/stdio_console.c and in ./arch/um/drivers/ssl.c, and not called directly Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 3f746c8eb0dd..bcc15f75646c 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -458,6 +458,10 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty) schedule_timeout_interruptible(timeout); } +/* Caller holds tty lock. + * NB: may drop and reacquire tty lock (in tty_wait_until_sent_from_close()) + * so tty and tty port may have changed state (but not hung up or reopened). + */ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp) { @@ -506,6 +510,7 @@ int tty_port_close_start(struct tty_port *port, } EXPORT_SYMBOL(tty_port_close_start); +/* Caller holds tty lock */ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) { unsigned long flags; @@ -528,6 +533,15 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) } EXPORT_SYMBOL(tty_port_close_end); +/** + * tty_port_close + * + * Caller holds tty lock + * + * NB: may drop and reacquire tty lock (in tty_port_close_start()-> + * tty_wait_until_sent_from_close()) so tty and tty_port may have changed + * state (but not hung up or reopened). + */ void tty_port_close(struct tty_port *port, struct tty_struct *tty, struct file *filp) { From addd4672bb442b23d16f91c5bae866ba1f9ffd4c Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:00 -0400 Subject: [PATCH 37/82] tty: Document locking for tty_port_open() The tty lock is held when the tty driver's open method is called (from the lone call-site, tty_open()). The call-tree audit [1] of tty_port_open() is a closed graph of the callers of tty_port_open(); ie., all callers originate from only tty_open(). Of these callers, none drop the tty lock. Also, document that tty_port_block_til_ready() may drop and reacquire the tty lock when blocking, which means the tty or tty_port may have changed state. [1] Call-tree audit of tty_port_open() tty_open() tty->ops->open() --+ | rs_open():arch/ia64/hp/sim/simserial.c *line_open():arch/um/drivers/line.c gdm_tty_open():drivers/staging/gdm724x/gdm_tty.c fwtty_open():drivers/staging/fwserial/fwserial.c acm_tty_open():drivers/usb/class/cdc-acm.c serial_open():drivers/usb/serial/usb-serial.c pti_tty_driver_open():drivers/misc/pti.c ipoctal_open():drivers/ipack/devices/ipoctal.c isicom_open():drivers/tty/isicom.c dashtty_open():drivers/tty/metag_da.c goldfish_tty_open():drivers/tty/goldfish.c ehv_bc_tty_open():drivers/tty/ehv_bytechan.c mxser_open():drivers/tty/mxser.c kgdb_nmi_tty_open():drivers/tty/serial/kgdb_nmi.c ifx_spi_open():drivers/tty/serial/ifx6x60.c smd_tty_open():drivers/tty/serial/msm_smd_tty.c ntty_open():drivers/tty/nozomi.c capinc_tty_open():drivers/isdn/capi/capi.c tpk_open():drivers/char/ttyprintk.c sdio_uart_open():drivers/mmc/card/sdio_uart.c rfcomm_tty_open():net/bluetooth/rfcomm/tty.c | +- tty_port_open() * line_open() is the .open method for 2 um drivers declared in ./arch/um/drivers/stdio_console.c and in ./arch/um/drivers/ssl.c, and not called directly Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index bcc15f75646c..f4698696abae 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -572,6 +572,14 @@ int tty_port_install(struct tty_port *port, struct tty_driver *driver, } EXPORT_SYMBOL_GPL(tty_port_install); +/** + * tty_port_open + * + * Caller holds tty lock. + * + * NB: may drop and reacquire tty lock (in tty_port_block_til_ready()) so + * tty and tty_port may have changed state (eg., may be hung up now) + */ int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp) { From c590f6b6cf04513c755b65bbeaf7bd1e88203bb0 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:01 -0400 Subject: [PATCH 38/82] tty: Document locking for tty_port_block_til_ready() The tty lock is held when the tty driver's open() method is called (from tty_open()). The call-tree audit [1] of tty_port_block_til_ready() is a closed graph of the callers of tty_port_block_til_ready(); ie., all callers originate only from tty_open(). Of these callers, none drop the tty lock. Also, document tty_port_block_til_ready() may drop and reacquire the tty lock when blocking, which means the tty or tty_port may have changed state. [1] Call-tree audit of tty_port_block_til_ready() * does not include call tree of tty_port_open() which is already documented in 'tty: Document locking from tty_port_open()' tty_open() tty->ops->open() --+ | cy_open():drivers/tty/cyclades.c rp_open():drivers/tty/rocket.c rs_open():drivers/tty/amiserial.c moxa_open():drivers/tty/moxa.c gsmtty_open():drivers/tty/n_gsm.c rs_open():drivers/tty/serial/68328serial.c uart_open():drivers/tty/serial/serial_core.c isdn_tty_open():drivers/isdn/i4l/isdn_tty.c mgslpc_open():drivers/char/pcmcia/synclink_cs.c | +- tty_port_block_til_ready() Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index f4698696abae..69e072b59127 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -348,6 +348,11 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts); * do carrier detect and the dtr_rts method if it supports software * management of these lines. Note that the dtr/rts raise is done each * iteration as a hangup may have previously dropped them while we wait. + * + * Caller holds tty lock. + * + * NB: May drop and reacquire tty lock when blocking, so tty and tty_port + * may have changed state (eg., may have been hung up). */ int tty_port_block_til_ready(struct tty_port *port, From 9c9928bded9b4e35326d608b636ac65ff16f0404 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:02 -0400 Subject: [PATCH 39/82] tty: Document locking for tty_port_hangup() The tty lock is held when the tty driver's hangup() method is called (from the lone call-site, __tty_hangup()). The call-tree audit [1] of tty_port_hangup() is a closed graph of the callers of tty_port_hangup(); ie., all callers originate only from __tty_hangup(). Of these callers, none drop the tty lock prior to calling tty_port_hangup(). [1] Call-tree audit of tty_port_hangup() __tty_hangup() tty->ops->hangup() --+ | rs_hangup():arch/ia64/hp/sim/simserial.c line_hangup():arch/um/drivers/line.c gdm_tty_hangup():drivers/staging/gdm724x/gdm_tty.c fwtty_hangup():drivers/staging/fwserial/fwserial.c acm_tty_hangup():drivers/usb/class/cdc-acm.c serial_hangup():drivers/usb/serial/usb-serial.c ipoctal_hangup():drivers/ipack/devices/ipoctal.c cy_hangup():drivers/tty/cyclades.c isicom_hangup():drivers/tty/isicom.c rp_hangup():drivers/tty/rocket.c dashtty_hangup():drivers/tty/metag_da.c moxa_hangup():drivers/tty/moxa.c gsmtty_hangup():drivers/tty/n_gsm.c goldfish_tty_hangup():drivers/tty/goldfish.c ehv_bc_tty_hangup():drivers/tty/ehv_bytechan.c mxser_hangup():drivers/tty/mxser.c kgdb_nmi_tty_hangup():drivers/tty/serial/kgdb_nmi.c ifx_spi_hangup():drivers/tty/serial/ifx6x60.c ntty_hangup():drivers/tty/nozomi.c capinc_tty_hangup():drivers/isdn/capi/capi.c mgslpc_hangup():drivers/char/pcmcia/synclink_cs.c sdio_uart_hangup():drivers/mmc/card/sdio_uart.c rfcomm_tty_hangup():net/bluetooth/rfcomm/tty.c | +- tty_port_hangup() Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 69e072b59127..7309594e1c12 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -227,6 +227,8 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) * * Perform port level tty hangup flag and count changes. Drop the tty * reference. + * + * Caller holds tty lock. */ void tty_port_hangup(struct tty_port *port) From ddc7b758a6765bd7f853b829104bb7a486a304ad Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:03 -0400 Subject: [PATCH 40/82] tty: Move tty->closing from port lock critical section tty->closing informs the line discipline that the hardware will be shutting down imminently, and to disable further input other than soft flow control (but to still allow additional output). However, the tty lock is the necessary lock for preventing concurrent changes to tty->closing. As shown by the call-tree audit [1] of functions that modify tty->closing, the tty lock is already held for those functions. [1] Call-tree audit of functions that modify tty->closing * does not include call tree to tty_port_close(), tty_port_close_start(), or tty_port_close_end() which is already documented in 'tty: Document locking for tty_port_close{,start,end}' that shows callers to those 3 functions hold the tty lock tty_release() tty->ops->close() --+ | __tty_hangup() | tty->ops->close() --+ | mp_close():drivers/staging/sb105x/sb_pci_mp.c dngc_tty_close():drivers/staging/dgnc/dgnc_tty.c dgap_tty_close():drivers/staging/dgap/dgap_tty.c dgrp_tty_close():drivers/staging/dgrp/dgrp_tty.c rp_close():drivers/tty/rocket.c hvsi_close():drivers/tty/hvc/hvsi.c rs_close():drivers/tty/serial/68328serial.c rs_close():drivers/tty/serial/crisv10.c uart_close():drivers/tty/serial/serial_core.c isdn_tty_close():drivers/isdn/i4l/isdn_tty.c tty3215_close():drivers/s390/char/con3215.c tty_open() tty_ldisc_setup() ----+ | __tty_hangup() | tty_ldisc_hangup() ---+ | tty_set_ldisc() --------+ tty_ldisc_restore() --+ | +- tty_ldisc_open() ld->ops->open() --+ | +- n_tty_open() Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 +- drivers/tty/tty_port.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 127ac6c8fd40..3e08df52d68d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1368,8 +1368,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty_port_tty_set(port, NULL); - spin_lock_irqsave(&port->lock, flags); tty->closing = 0; + spin_lock_irqsave(&port->lock, flags); if (port->blocked_open) { spin_unlock_irqrestore(&port->lock, flags); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 7309594e1c12..9209d6331b8e 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -497,9 +497,10 @@ int tty_port_close_start(struct tty_port *port, return 0; } set_bit(ASYNCB_CLOSING, &port->flags); - tty->closing = 1; spin_unlock_irqrestore(&port->lock, flags); + tty->closing = 1; + if (test_bit(ASYNCB_INITIALIZED, &port->flags)) { /* Don't block on a stalled port, just pull the chain */ if (tty->flow_stopped) @@ -522,9 +523,10 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); tty->closing = 0; + spin_lock_irqsave(&port->lock, flags); + if (port->blocked_open) { spin_unlock_irqrestore(&port->lock, flags); if (port->close_delay) { From 01261cb943182fb9e8e7be670ec879426013e938 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:04 -0400 Subject: [PATCH 41/82] tty: ipwireless: Remove tty->closing abort from ipw_open() tty->closing cannot be set on ipw_open() because the ipwireless tty driver does not call any functions that set tty->closing. CC: Jiri Kosina Signed-off-by: Peter Hurley Acked-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- drivers/tty/ipwireless/tty.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 17ee3bf0926b..345cebb07ae7 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -93,11 +93,6 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) return -ENODEV; mutex_lock(&tty->ipw_tty_mutex); - - if (tty->closing) { - mutex_unlock(&tty->ipw_tty_mutex); - return -ENODEV; - } if (tty->port.count == 0) tty->tx_bytes_queued = 0; From 5fda7a0e715c32c6dd9a39ebce8429eeafb64b7d Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:05 -0400 Subject: [PATCH 42/82] serial: Use UPF_* constants with struct uart_port flags Fix ASYNC_* constant usage that should be the corresponding UPF_* constant. CC: Grant Likely CC: Rob Herring CC: devicetree@vger.kernel.org Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/lantiq.c | 2 +- drivers/tty/serial/mcf.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index ea030830cfa2..4675fe198d31 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -703,7 +703,7 @@ lqasc_probe(struct platform_device *pdev) port = <q_port->port; port->iotype = SERIAL_IO_MEM; - port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP; + port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->ops = &lqasc_pops; port->fifosize = 16; port->type = PORT_LTQ_ASC, diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index fab4d6ad16ef..bc896dc7d2ed 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -537,7 +537,7 @@ int __init early_mcf_setup(struct mcf_platform_uart *platp) port->iotype = SERIAL_IO_MEM; port->irq = platp[i].irq; port->uartclk = MCF_BUSCLK; - port->flags = ASYNC_BOOT_AUTOCONF; + port->flags = UPF_BOOT_AUTOCONF; port->ops = &mcf_uart_ops; } @@ -662,7 +662,7 @@ static int mcf_probe(struct platform_device *pdev) port->irq = platp[i].irq; port->uartclk = MCF_BUSCLK; port->ops = &mcf_uart_ops; - port->flags = ASYNC_BOOT_AUTOCONF; + port->flags = UPF_BOOT_AUTOCONF; uart_add_one_port(&mcf_driver, port); } From e359a4e38d229d53e28905863a1fabf41debd591 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:06 -0400 Subject: [PATCH 43/82] tty: Remove tty_hung_up_p() tests from tty drivers' open() Since at least before 2.6.30, it has not been possible to observe a hung up file pointer in a tty driver's open() method unless/until the driver open() releases the tty_lock() (eg., before blocking). This is because tty_open() adds the file pointer while holding the tty_lock() _and_ doesn't release the lock until after calling the tty driver's open() method. [ Before tty_lock(), this was lock_kernel(). ] Since __tty_hangup() first waits on the tty_lock() before enumerating and hanging up the open file pointers, either __tty_hangup() will wait for the tty_lock() or tty_open() will not yet have added the file pointer. For example, CPU 0 | CPU 1 | tty_open | __tty_hangup .. | .. tty_lock | .. tty_reopen | tty_lock / blocks .. | tty_add_file(tty, filp) | .. | tty->ops->open(tty, filp) | tty_port_open | tty_port_block_til_ready | .. | while (1) | .. | tty_unlock | / unblocks schedule | for each filp on tty->tty_files | f_ops = tty_hung_up_fops; | .. | tty_unlock tty_lock | .. | tty_unlock | Note that since tty_port_block_til_ready() and similar drop the tty_lock while blocking, when woken, the file pointer must then be tested for having been hung up. Also, fix bit-rotted drivers that used extra_count to track the port->count bump. CC: Mikael Starvik CC: Samuel Ortiz CC: "David S. Miller" Signed-off-by: Peter Hurley Acked-by: Jesper Nilsson Signed-off-by: Greg Kroah-Hartman --- drivers/char/pcmcia/synclink_cs.c | 2 +- drivers/staging/dgrp/dgrp_tty.c | 10 ---------- drivers/tty/cyclades.c | 2 +- drivers/tty/serial/crisv10.c | 15 +++++---------- drivers/tty/serial/serial_core.c | 8 -------- drivers/tty/synclink.c | 10 +++------- drivers/tty/synclink_gt.c | 10 +++------- drivers/tty/synclinkmp.c | 11 +++-------- drivers/tty/tty_port.c | 8 +++----- net/irda/ircomm/ircomm_tty.c | 6 ++---- 10 files changed, 21 insertions(+), 61 deletions(-) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 8320abd1ef14..a63970f76967 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2510,7 +2510,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) __FILE__, __LINE__, tty->driver->name, port->count); /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING){ + if (port->flags & ASYNC_CLOSING){ wait_event_interruptible_tty(tty, port->close_wait, !(port->flags & ASYNC_CLOSING)); retval = ((port->flags & ASYNC_HUP_NOTIFY) ? diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c index 30d26029b21e..cdd1a69261dd 100644 --- a/drivers/staging/dgrp/dgrp_tty.c +++ b/drivers/staging/dgrp/dgrp_tty.c @@ -631,16 +631,6 @@ static int dgrp_tty_open(struct tty_struct *tty, struct file *file) un->un_tty = tty; tty->driver_data = un; - /* - * If we are in the middle of hanging up, - * then return an error - */ - if (tty_hung_up_p(file)) { - retval = ((un->un_flag & UN_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - goto done; - } - /* * If the port is in the middle of closing, then block * until it is done, then try again. diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index a57bb5ab761c..fd66f57390d0 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1579,7 +1579,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) /* * If the port is the middle of closing, bail out now */ - if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { + if (info->port.flags & ASYNC_CLOSING) { wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index d567ac5d3af4..58e6f61a87e4 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -3831,14 +3831,13 @@ block_til_ready(struct tty_struct *tty, struct file * filp, DECLARE_WAITQUEUE(wait, current); unsigned long flags; int retval; - int do_clocal = 0, extra_count = 0; + int do_clocal = 0; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ - if (tty_hung_up_p(filp) || - (info->port.flags & ASYNC_CLOSING)) { + if (info->port.flags & ASYNC_CLOSING) { wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART @@ -3879,10 +3878,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, info->line, info->port.count); #endif local_irq_save(flags); - if (!tty_hung_up_p(filp)) { - extra_count++; - info->port.count--; - } + info->port.count--; local_irq_restore(flags); info->port.blocked_open++; while (1) { @@ -3921,7 +3917,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, } set_current_state(TASK_RUNNING); remove_wait_queue(&info->port.open_wait, &wait); - if (extra_count) + if (!tty_hung_up_p(filp)) info->port.count++; info->port.blocked_open--; #ifdef SERIAL_DEBUG_OPEN @@ -3976,8 +3972,7 @@ rs_open(struct tty_struct *tty, struct file * filp) /* * If the port is in the middle of closing, bail out now */ - if (tty_hung_up_p(filp) || - (info->port.flags & ASYNC_CLOSING)) { + if (info->port.flags & ASYNC_CLOSING) { wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 3e08df52d68d..1a5fbf7ab347 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1583,14 +1583,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp) (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; tty_port_tty_set(port, tty); - /* - * If the port is in the middle of closing, bail out now. - */ - if (tty_hung_up_p(filp)) { - retval = -EAGAIN; - goto err_dec_count; - } - /* * Start up the serial port. */ diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index d48e040cd8c5..b7991707ffc0 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3267,7 +3267,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, DECLARE_WAITQUEUE(wait, current); int retval; bool do_clocal = false; - bool extra_count = false; unsigned long flags; int dcd; struct tty_port *port = &info->port; @@ -3300,10 +3299,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, __FILE__,__LINE__, tty->driver->name, port->count ); spin_lock_irqsave(&info->irq_spinlock, flags); - if (!tty_hung_up_p(filp)) { - extra_count = true; - port->count--; - } + port->count--; spin_unlock_irqrestore(&info->irq_spinlock, flags); port->blocked_open++; @@ -3342,7 +3338,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, remove_wait_queue(&port->open_wait, &wait); /* FIXME: Racy on hangup during close wait */ - if (extra_count) + if (!tty_hung_up_p(filp)) port->count++; port->blocked_open--; @@ -3403,7 +3399,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) __FILE__,__LINE__,tty->driver->name, info->port.count); /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ + if (info->port.flags & ASYNC_CLOSING){ wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index c359a91f7346..ba1dbcdf4609 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -673,7 +673,7 @@ static int open(struct tty_struct *tty, struct file *filp) DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count)); /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ + if (info->port.flags & ASYNC_CLOSING){ wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? @@ -3273,7 +3273,6 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, DECLARE_WAITQUEUE(wait, current); int retval; bool do_clocal = false; - bool extra_count = false; unsigned long flags; int cd; struct tty_port *port = &info->port; @@ -3300,10 +3299,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, add_wait_queue(&port->open_wait, &wait); spin_lock_irqsave(&info->lock, flags); - if (!tty_hung_up_p(filp)) { - extra_count = true; - port->count--; - } + port->count--; spin_unlock_irqrestore(&info->lock, flags); port->blocked_open++; @@ -3338,7 +3334,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); - if (extra_count) + if (!tty_hung_up_p(filp)) port->count++; port->blocked_open--; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 53ba8537de8d..c3f90910fed9 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -753,7 +753,7 @@ static int open(struct tty_struct *tty, struct file *filp) __FILE__,__LINE__,tty->driver->name, info->port.count); /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ + if (info->port.flags & ASYNC_CLOSING){ wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? @@ -3288,7 +3288,6 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, DECLARE_WAITQUEUE(wait, current); int retval; bool do_clocal = false; - bool extra_count = false; unsigned long flags; int cd; struct tty_port *port = &info->port; @@ -3322,10 +3321,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, __FILE__,__LINE__, tty->driver->name, port->count ); spin_lock_irqsave(&info->lock, flags); - if (!tty_hung_up_p(filp)) { - extra_count = true; - port->count--; - } + port->count--; spin_unlock_irqrestore(&info->lock, flags); port->blocked_open++; @@ -3362,8 +3358,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); - - if (extra_count) + if (!tty_hung_up_p(filp)) port->count++; port->blocked_open--; diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 9209d6331b8e..1b9335796da4 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -365,7 +365,7 @@ int tty_port_block_til_ready(struct tty_port *port, DEFINE_WAIT(wait); /* block if port is in the process of being closed */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { + if (port->flags & ASYNC_CLOSING) { wait_event_interruptible_tty(tty, port->close_wait, !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) @@ -399,8 +399,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* The port lock protects the port counts */ spin_lock_irqsave(&port->lock, flags); - if (!tty_hung_up_p(filp)) - port->count--; + port->count--; port->blocked_open++; spin_unlock_irqrestore(&port->lock, flags); @@ -593,8 +592,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp) { spin_lock_irq(&port->lock); - if (!tty_hung_up_p(filp)) - ++port->count; + ++port->count; spin_unlock_irq(&port->lock); tty_port_tty_set(port, tty); diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 2ba8b9705bb7..61ceb4cdb4a2 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -320,8 +320,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, __FILE__, __LINE__, tty->driver->name, port->count); spin_lock_irqsave(&port->lock, flags); - if (!tty_hung_up_p(filp)) - port->count--; + port->count--; port->blocked_open++; spin_unlock_irqrestore(&port->lock, flags); @@ -458,8 +457,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) /* * If the port is the middle of closing, bail out now */ - if (tty_hung_up_p(filp) || - test_bit(ASYNCB_CLOSING, &self->port.flags)) { + if (test_bit(ASYNCB_CLOSING, &self->port.flags)) { /* Hm, why are we blocking on ASYNC_CLOSING if we * do return -EAGAIN/-ERESTARTSYS below anyway? From 69fee6885f6042d0d3d3773b208a84e7bb161650 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:07 -0400 Subject: [PATCH 44/82] char: synclink: Remove WARN_ON for bad port count tty_port_close_start() already validates the port counts and issues a diagnostic if validation fails. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/char/pcmcia/synclink_cs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index a63970f76967..0ea9986059af 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2347,8 +2347,6 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp) printk("%s(%d):mgslpc_close(%s) entry, count=%d\n", __FILE__, __LINE__, info->device_name, port->count); - WARN_ON(!port->count); - if (tty_port_close_start(port, tty, filp) == 0) goto cleanup; From 7c6d340f4f0e889b134fd72f203519f591feef9d Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:08 -0400 Subject: [PATCH 45/82] tty: Call hangup method in modern style Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 34110719fe03..714320b5e525 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -688,7 +688,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) for (n = 0; n < closecount; n++) tty->ops->close(tty, cons_filp); } else if (tty->ops->hangup) - (tty->ops->hangup)(tty); + tty->ops->hangup(tty); /* * We don't want to have driver/ldisc interactions beyond * the ones we did here. The driver layer expects no From c18b55fd1717a4c08c9f3555be63da142767e6b8 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:09 -0400 Subject: [PATCH 46/82] tty: serial: Fix termios/port flags mismatch Uart port drivers may reconfigure termios settings based on available hardware support; set/clear ASYNC_CTS_FLOW and ASYNC_CHECK_CD _after_ calling the port driver's .set_termios method. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 1a5fbf7ab347..b70095e55df6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -450,6 +450,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, return; termios = &tty->termios; + uport->ops->set_termios(uport, termios, old_termios); /* * Set flags based on termios cflag @@ -463,8 +464,6 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, clear_bit(ASYNCB_CHECK_CD, &port->flags); else set_bit(ASYNCB_CHECK_CD, &port->flags); - - uport->ops->set_termios(uport, termios, old_termios); } static inline int __uart_put_char(struct uart_port *port, @@ -1282,6 +1281,8 @@ static void uart_set_termios(struct tty_struct *tty, } uart_change_speed(tty, state, old_termios); + /* reload cflag from termios; port driver may have overriden flags */ + cflag = tty->termios.c_cflag; /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) From 8bd67d7d2cbcea2a2371480fe3fe47f2bcd0294c Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 16 Jun 2014 09:17:10 -0400 Subject: [PATCH 47/82] serial: blackfin: Fix CTS flow control blackfin uart port drivers mistakenly set the struct uart_port flags bit UPF_BUG_THRE (which only has meaning to the 8250 core) while trying to set ASYNC_CTS_FLOW. Uart port drivers can override termios settings based on actual hardware support in their .set_termios method; the serial core sets the appropriate port flags based on the overrides. Overriding only the initial termios settings is accomplished by only perform those overrides if the old termios parameter is NULL. CC: Sonic Zhang CC: adi-buildroot-devel@lists.sourceforge.net Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/bfin_sport_uart.c | 11 ++++++++--- drivers/tty/serial/bfin_uart.c | 13 ++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index 1174efa466a6..7810aa290edf 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -495,6 +495,13 @@ static void sport_set_termios(struct uart_port *port, pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); +#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS + if (old == NULL && up->cts_pin != -1) + termios->c_cflag |= CRTSCTS; + else if (up->cts_pin == -1) + termios->c_cflag &= ~CRTSCTS; +#endif + switch (termios->c_cflag & CSIZE) { case CS8: up->csize = 8; @@ -807,10 +814,8 @@ static int sport_uart_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res == NULL) sport->cts_pin = -1; - else { + else sport->cts_pin = res->start; - sport->port.flags |= ASYNC_CTS_FLOW; - } res = platform_get_resource(pdev, IORESOURCE_IO, 1); if (res == NULL) diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index dddc081568f1..dec0fd725d80 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -785,6 +785,13 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int ier, lcr = 0; unsigned long timeout; +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (old == NULL && uart->cts_pin != -1) + termios->c_cflag |= CRTSCTS; + else if (uart->cts_pin == -1) + termios->c_cflag &= ~CRTSCTS; +#endif + switch (termios->c_cflag & CSIZE) { case CS8: lcr = WLS(8); @@ -1316,12 +1323,8 @@ static int bfin_serial_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res == NULL) uart->cts_pin = -1; - else { + else uart->cts_pin = res->start; -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - uart->port.flags |= ASYNC_CTS_FLOW; -#endif - } res = platform_get_resource(pdev, IORESOURCE_IO, 1); if (res == NULL) From db3a1a43fbb3c0e2f993ce5e7305641075eeb1d6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 9 Jun 2014 18:11:21 +0300 Subject: [PATCH 48/82] serial: txx9: remove duplicate TXX9_SIFCR_TDIL_MASK define The TXX9_SIFCR_TDIL_MASK define is cut and pasted twice so we can delete the second instance. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_txx9.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 29f5232f79e4..af115645c51f 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -142,7 +142,6 @@ struct uart_txx9_port { #define TXX9_SIFCR_RDIL_12 0x00000180 #define TXX9_SIFCR_RDIL_MAX 0x00000180 #define TXX9_SIFCR_TDIL_MASK 0x00000018 -#define TXX9_SIFCR_TDIL_MASK 0x00000018 #define TXX9_SIFCR_TDIL_1 0x00000000 #define TXX9_SIFCR_TDIL_4 0x00000001 #define TXX9_SIFCR_TDIL_8 0x00000010 From 68252424a7c757ce0a534696e22e1770408bc01d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 30 Jun 2014 14:54:01 -0700 Subject: [PATCH 49/82] tty: serial: msm: Support big-endian CPUs To support big-endian CPUs use the string versions of the io read/write macros on the TX/RX fifos and the non-raw variants of the readl/writel macros throughout. This way we don't byteswap the characters coming from the fifos but we properly deal with the little-endian nature of the serial hardware while controlling it. Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 28 ++++++++++++++++++---------- drivers/tty/serial/msm_serial.h | 4 ++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 90feee190f2a..c549110509bb 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -125,14 +125,14 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr) port->icount.rx += count; while (count > 0) { - unsigned int c; + unsigned char buf[4]; sr = msm_read(port, UART_SR); if ((sr & UART_SR_RX_READY) == 0) { msm_port->old_snap_state -= count; break; } - c = msm_read(port, UARTDM_RF); + ioread32_rep(port->membase + UARTDM_RF, buf, 1); if (sr & UART_SR_RX_BREAK) { port->icount.brk++; if (uart_handle_break(port)) @@ -141,8 +141,7 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr) port->icount.frame++; /* TODO: handle sysrq */ - tty_insert_flip_string(tport, (char *)&c, - (count > 4) ? 4 : count); + tty_insert_flip_string(tport, buf, min(count, 4)); count -= 4; } @@ -219,6 +218,12 @@ static void handle_tx(struct uart_port *port) struct msm_port *msm_port = UART_TO_MSM(port); unsigned int tx_count, num_chars; unsigned int tf_pointer = 0; + void __iomem *tf; + + if (msm_port->is_uartdm) + tf = port->membase + UARTDM_TF; + else + tf = port->membase + UART_TF; tx_count = uart_circ_chars_pending(xmit); tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail, @@ -228,8 +233,7 @@ static void handle_tx(struct uart_port *port) if (msm_port->is_uartdm) reset_dm_count(port, tx_count + 1); - msm_write(port, port->x_char, - msm_port->is_uartdm ? UARTDM_TF : UART_TF); + iowrite8_rep(tf, &port->x_char, 1); port->icount.tx++; port->x_char = 0; } else if (tx_count && msm_port->is_uartdm) { @@ -239,7 +243,6 @@ static void handle_tx(struct uart_port *port) while (tf_pointer < tx_count) { int i; char buf[4] = { 0 }; - unsigned int *bf = (unsigned int *)&buf; if (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) break; @@ -255,7 +258,7 @@ static void handle_tx(struct uart_port *port) port->icount.tx++; } - msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + iowrite32_rep(tf, buf, 1); xmit->tail = (xmit->tail + num_chars) & (UART_XMIT_SIZE - 1); tf_pointer += num_chars; } @@ -861,12 +864,18 @@ static void msm_console_write(struct console *co, const char *s, struct msm_port *msm_port; int num_newlines = 0; bool replaced = false; + void __iomem *tf; BUG_ON(co->index < 0 || co->index >= UART_NR); port = get_port_from_line(co->index); msm_port = UART_TO_MSM(port); + if (msm_port->is_uartdm) + tf = port->membase + UARTDM_TF; + else + tf = port->membase + UART_TF; + /* Account for newlines that will get a carriage return added */ for (i = 0; i < count; i++) if (s[i] == '\n') @@ -882,7 +891,6 @@ static void msm_console_write(struct console *co, const char *s, int j; unsigned int num_chars; char buf[4] = { 0 }; - unsigned int *bf = (unsigned int *)&buf; if (msm_port->is_uartdm) num_chars = min(count - i, (unsigned int)sizeof(buf)); @@ -907,7 +915,7 @@ static void msm_console_write(struct console *co, const char *s, while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) cpu_relax(); - msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + iowrite32_rep(tf, buf, 1); i += num_chars; } spin_unlock(&port->lock); diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index d98d45efdf86..73d3abe71e79 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h @@ -126,13 +126,13 @@ static inline void msm_write(struct uart_port *port, unsigned int val, unsigned int off) { - __raw_writel(val, port->membase + off); + writel_relaxed(val, port->membase + off); } static inline unsigned int msm_read(struct uart_port *port, unsigned int off) { - return __raw_readl(port->membase + off); + return readl_relaxed(port->membase + off); } /* From d36f47fa841984691a05ca6477dd26064963048c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 11 Jul 2014 10:16:45 +0200 Subject: [PATCH 50/82] serial: efm32: correct namespacing of location property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Olof Johansson pointed out that usually the company name is picked as namespace prefix to specific properties. So expect "energymicro,location" but fall back to the previously introduced name "efm32,location". Cc: Olof Johansson Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/efm32-uart.txt | 4 ++-- drivers/tty/serial/efm32-uart.c | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/efm32-uart.txt b/Documentation/devicetree/bindings/serial/efm32-uart.txt index 3ca01336b837..8adbab268ca3 100644 --- a/Documentation/devicetree/bindings/serial/efm32-uart.txt +++ b/Documentation/devicetree/bindings/serial/efm32-uart.txt @@ -6,7 +6,7 @@ Required properties: - interrupts : Should contain uart interrupt Optional properties: -- efm32,location : Decides the location of the USART I/O pins. +- energymicro,location : Decides the location of the USART I/O pins. Allowed range : [0 .. 5] Default: 0 @@ -16,5 +16,5 @@ uart@0x4000c400 { compatible = "energymicro,efm32-uart"; reg = <0x4000c400 0x400>; interrupts = <15>; - efm32,location = <0>; + energymicro,location = <0>; }; diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 7baa34920dbf..55d9c00112cc 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -665,10 +665,16 @@ static int efm32_uart_probe_dt(struct platform_device *pdev, if (!np) return 1; - ret = of_property_read_u32(np, "efm32,location", &location); + ret = of_property_read_u32(np, "energymicro,location", &location); + + if (ret) + /* fall back to wrongly namespaced property */ + ret = of_property_read_u32(np, "efm32,location", &location); + if (ret) /* fall back to old and (wrongly) generic property "location" */ ret = of_property_read_u32(np, "location", &location); + if (!ret) { if (location > 5) { dev_err(&pdev->dev, "invalid location\n"); From 2970b7f5ea3cea2f169ca23fd863e24d03748ffd Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Fri, 11 Jul 2014 14:00:11 +0100 Subject: [PATCH 51/82] serial: altera: Adopt uart_console_write() This driver does not currently use uart_console_write() and instead provides is own LF to LFCR conversion in it's console_write() method. We should use the library function instead. Cmopile tested only (with ARCH=arm). Signed-off-by: Daniel Thompson Cc: Tobias Klauser Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Cc: nios2-dev@lists.rocketboards.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/altera_uart.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 4c1eae93110c..6a243239dbef 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -430,7 +430,7 @@ static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS]; #if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) -static void altera_uart_console_putc(struct uart_port *port, const char c) +static void altera_uart_console_putc(struct uart_port *port, int c) { while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_TRDY_MSK)) @@ -444,11 +444,7 @@ static void altera_uart_console_write(struct console *co, const char *s, { struct uart_port *port = &(altera_uart_ports + co->index)->port; - for (; count; count--, s++) { - altera_uart_console_putc(port, *s); - if (*s == '\n') - altera_uart_console_putc(port, '\r'); - } + uart_console_write(port, s, count, altera_uart_console_putc); } static int __init altera_uart_console_setup(struct console *co, char *options) From f363ca2fc8d12ebaad1a8bdae0f164c17c747b89 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 11 Jul 2014 18:31:37 +0530 Subject: [PATCH 52/82] serial/arc: Fix warning with CONSOLE_POLL | drivers/tty/serial/arc_uart.c:516:2: warning: (near initialization for 'arc_serial_pops.poll_put_char') [enabled by default] This partially undoes "serial/arc: use uart_console_write() helper" by restoring the prototpye of poll helper and use a different one in uart_console_write() Signed-off-by: Vineet Gupta Reported-by: kbuild test robot Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 3a504fb9c9e8..f8dc7d381956 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -442,18 +442,16 @@ static void arc_serial_config_port(struct uart_port *port, int flags) port->type = PORT_ARC; } -#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE) +#ifdef CONFIG_CONSOLE_POLL -static void arc_serial_poll_putchar(struct uart_port *port, int chr) +static void arc_serial_poll_putchar(struct uart_port *port, unsigned char chr) { while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); - UART_SET_DATA(port, (unsigned char)chr); + UART_SET_DATA(port, chr); } -#endif -#ifdef CONFIG_CONSOLE_POLL static int arc_serial_poll_getchar(struct uart_port *port) { unsigned char chr; @@ -519,6 +517,14 @@ static int arc_serial_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } +static void arc_serial_console_putchar(struct uart_port *port, int ch) +{ + while (!(UART_GET_STATUS(port) & TXEMPTY)) + cpu_relax(); + + UART_SET_DATA(port, (unsigned char)ch); +} + /* * Interrupts are disabled on entering */ @@ -529,7 +535,7 @@ static void arc_serial_console_write(struct console *co, const char *s, unsigned long flags; spin_lock_irqsave(&port->lock, flags); - uart_console_write(port, s, count, arc_serial_poll_putchar); + uart_console_write(port, s, count, arc_serial_console_putchar); spin_unlock_irqrestore(&port->lock, flags); } @@ -548,7 +554,7 @@ static __init void arc_early_serial_write(struct console *con, const char *s, { struct earlycon_device *dev = con->data; - uart_console_write(&dev->port, s, n, arc_serial_poll_putchar); + uart_console_write(&dev->port, s, n, arc_serial_console_putchar); } static int __init arc_early_console_setup(struct earlycon_device *dev, From 493671a2cecbb75d5b1aee6959bef1ecb38b932d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 11 Jul 2014 18:13:26 +0200 Subject: [PATCH 53/82] serial: pch_uart: Update error message for dmaengine_prep_slave_sg() API Commit 16052827d98fbc13c31ebad560af4bd53e2b4dd5 ("dmaengine/dma_slave: introduce inline wrappers") changed the code to use the new API, but forgot to update an error message. Signed-off-by: Geert Uytterhoeven Cc: Jiri Kosina Cc: linux-serial@vger.kernel.org -- v2: - New Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 0cb6a8e52bd0..2f06e5a71396 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1047,7 +1047,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) priv->sg_tx_p, nent, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { - dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n", + dev_err(priv->port.dev, "%s:dmaengine_prep_slave_sg Failed\n", __func__); return 0; } From 2c964a2f4191f2229566895f1a0e85f8339f5dd1 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 10 Jul 2014 21:01:22 +0200 Subject: [PATCH 54/82] drivers: tty: Merge alloc_tty_struct and initialize_tty_struct The two functions alloc_tty_struct and initialize_tty_struct are always called together. Merge them into alloc_tty_struct, updating its prototype and the only two callers of these functions. Signed-off-by: Rasmus Villemoes Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 19 +++++++++---------- drivers/tty/tty_io.c | 37 +++++++++++++------------------------ include/linux/tty.h | 4 +--- 3 files changed, 23 insertions(+), 37 deletions(-) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 25c9bc783722..ac723e3c031a 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -316,7 +316,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws) * pty_common_install - set up the pty pair * @driver: the pty driver * @tty: the tty being instantiated - * @bool: legacy, true if this is BSD style + * @legacy: true if this is BSD style * * Perform the initial set up for the tty/pty pair. Called from the * tty layer when the port is first opened. @@ -331,18 +331,17 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, int idx = tty->index; int retval = -ENOMEM; - o_tty = alloc_tty_struct(); - if (!o_tty) - goto err; ports[0] = kmalloc(sizeof **ports, GFP_KERNEL); ports[1] = kmalloc(sizeof **ports, GFP_KERNEL); if (!ports[0] || !ports[1]) - goto err_free_tty; + goto err; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ - goto err_free_tty; + goto err; } - initialize_tty_struct(o_tty, driver->other, idx); + o_tty = alloc_tty_struct(driver->other, idx); + if (!o_tty) + goto err_put_module; if (legacy) { /* We always use new tty termios data so we can do this @@ -387,12 +386,12 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, tty_free_termios(tty); err_deinit_tty: deinitialize_tty_struct(o_tty); + free_tty_struct(o_tty); +err_put_module: module_put(o_tty->driver->owner); -err_free_tty: +err: kfree(ports[0]); kfree(ports[1]); - free_tty_struct(o_tty); -err: return retval; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 714320b5e525..8fbad3410c75 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -156,20 +156,6 @@ static void release_tty(struct tty_struct *tty, int idx); static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); -/** - * alloc_tty_struct - allocate a tty object - * - * Return a new empty tty structure. The data fields have not - * been initialized in any way but has been zeroed - * - * Locking: none - */ - -struct tty_struct *alloc_tty_struct(void) -{ - return kzalloc(sizeof(struct tty_struct), GFP_KERNEL); -} - /** * free_tty_struct - free a disused tty * @tty: tty struct to free @@ -1455,12 +1441,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) if (!try_module_get(driver->owner)) return ERR_PTR(-ENODEV); - tty = alloc_tty_struct(); + tty = alloc_tty_struct(driver, idx); if (!tty) { retval = -ENOMEM; goto err_module_put; } - initialize_tty_struct(tty, driver, idx); tty_lock(tty); retval = tty_driver_install_tty(driver, tty); @@ -3003,19 +2988,21 @@ static struct device *tty_get_device(struct tty_struct *tty) /** - * initialize_tty_struct - * @tty: tty to initialize + * alloc_tty_struct * - * This subroutine initializes a tty structure that has been newly - * allocated. + * This subroutine allocates and initializes a tty structure. * - * Locking: none - tty in question must not be exposed at this point + * Locking: none - tty in question is not exposed at this point */ -void initialize_tty_struct(struct tty_struct *tty, - struct tty_driver *driver, int idx) +struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) { - memset(tty, 0, sizeof(struct tty_struct)); + struct tty_struct *tty; + + tty = kzalloc(sizeof(*tty), GFP_KERNEL); + if (!tty) + return NULL; + kref_init(&tty->kref); tty->magic = TTY_MAGIC; tty_ldisc_init(tty); @@ -3039,6 +3026,8 @@ void initialize_tty_struct(struct tty_struct *tty, tty->index = idx; tty_line_name(driver, idx, tty->name); tty->dev = tty_get_device(tty); + + return tty; } /** diff --git a/include/linux/tty.h b/include/linux/tty.h index 1c3316a47d7e..84132942902a 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -477,13 +477,11 @@ extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg); extern void tty_default_fops(struct file_operations *fops); -extern struct tty_struct *alloc_tty_struct(void); +extern struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx); extern int tty_alloc_file(struct file *file); extern void tty_add_file(struct tty_struct *tty, struct file *file); extern void tty_free_file(struct file *file); extern void free_tty_struct(struct tty_struct *tty); -extern void initialize_tty_struct(struct tty_struct *tty, - struct tty_driver *driver, int idx); extern void deinitialize_tty_struct(struct tty_struct *tty); extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); extern int tty_release(struct inode *inode, struct file *filp); From 07584d4a356ef52c084e1e4fedc22858ffc2f8b2 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Sun, 13 Jul 2014 01:44:00 +0200 Subject: [PATCH 55/82] drivers: tty: Fix use-after-free in pty_common_install In 2c964a2f "drivers: tty: Merge alloc_tty_struct and initialize_tty_struct", I messed up the refactorization of pty_common_install, causing use-after-free and NULL pointer derefs on various error paths. This should fix it. Reported-by: Julia Lawall Reported-by: Dan Carpenter Signed-off-by: Rasmus Villemoes Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index ac723e3c031a..9bbdb1de12e2 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -388,7 +388,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, deinitialize_tty_struct(o_tty); free_tty_struct(o_tty); err_put_module: - module_put(o_tty->driver->owner); + module_put(driver->other->owner); err: kfree(ports[0]); kfree(ports[1]); From b7d66397f4d282ddf2a2fe516fc9329c5a063459 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 14 Jul 2014 16:09:58 +0900 Subject: [PATCH 56/82] serial: sh-sci: Updated calculation of bit error rate and bit rate Currently, the decimal point is discarded calculation of BRR. Therefore, it can not calculate a value close to the correct value. This patch fixes this problem by using DIV_ROUND_CLOSEST. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 26dad3e87b52..2ba42069922f 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1789,11 +1789,13 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, for (sr = 8; sr <= 32; sr++) { for (c = 0; c <= 3; c++) { /* integerized formulas from HSCIF documentation */ - br = freq / (sr * (1 << (2 * c + 1)) * bps) - 1; + br = DIV_ROUND_CLOSEST(freq, (sr * + (1 << (2 * c + 1)) * bps)) - 1; if (br < 0 || br > 255) continue; - err = freq / ((br + 1) * bps * sr * - (1 << (2 * c + 1)) / 1000) - 1000; + err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr * + (1 << (2 * c + 1)) / 1000)) - + 1000; if (min_err > err) { min_err = err; *brr = br; From bcb9973a6097652a12660958449301aada41de9c Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 14 Jul 2014 16:09:59 +0900 Subject: [PATCH 57/82] serial: sh-sci: Fix range check of bit-rate for HSCIF If bit-rate calculation result of HSCIF is expect 255 from 0, driver does not calculate error bit. However, we need to round the value to calculate error bit in the case of negative value. This rounds the value of bit-rate using clamp(), and bit-rate is the case of negative value, it enables the calculation of the error bit. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 2ba42069922f..091b65587c7c 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1791,8 +1791,7 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, /* integerized formulas from HSCIF documentation */ br = DIV_ROUND_CLOSEST(freq, (sr * (1 << (2 * c + 1)) * bps)) - 1; - if (br < 0 || br > 255) - continue; + br = clamp(br, 0, 255); err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr * (1 << (2 * c + 1)) / 1000)) - 1000; From 730c4e782c039caf40b467c35f595c005e94220c Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 14 Jul 2014 16:10:00 +0900 Subject: [PATCH 58/82] serial: sh-sci: Add calculation recive margin for HSCIF When the error of the same bit rate is detected, we will need to select the recive margin is large. Current code holds the minimum error, it does not have to check the recive margin. This adds this calculation. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 77 ++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 091b65587c7c..3081e46085ce 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1776,13 +1776,30 @@ static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, return ((freq + 16 * bps) / (32 * bps) - 1); } +/* calculate frame length from SMR */ +static int sci_baud_calc_frame_len(unsigned int smr_val) +{ + int len = 10; + + if (smr_val & SCSMR_CHR) + len--; + if (smr_val & SCSMR_PE) + len++; + if (smr_val & SCSMR_STOP) + len++; + + return len; +} + + /* calculate sample rate, BRR, and clock select for HSCIF */ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, int *brr, unsigned int *srr, - unsigned int *cks) + unsigned int *cks, int frame_len) { - int sr, c, br, err; + int sr, c, br, err, recv_margin; int min_err = 1000; /* 100% */ + int recv_max_margin = 0; /* Find the combination of sample rate and clock select with the smallest deviation from the desired baud rate. */ @@ -1795,12 +1812,35 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr * (1 << (2 * c + 1)) / 1000)) - 1000; + if (err < 0) + continue; + + /* Calc recv margin + * M: Receive margin (%) + * N: Ratio of bit rate to clock (N = sampling rate) + * D: Clock duty (D = 0 to 1.0) + * L: Frame length (L = 9 to 12) + * F: Absolute value of clock frequency deviation + * + * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) - + * (|D - 0.5| / N * (1 + F))| + * NOTE: Usually, treat D for 0.5, F is 0 by this + * calculation. + */ + recv_margin = abs((500 - + DIV_ROUND_CLOSEST(1000, sr << 1)) / 10); if (min_err > err) { min_err = err; - *brr = br; - *srr = sr - 1; - *cks = c; - } + recv_max_margin = recv_margin; + } else if ((min_err == err) && + (recv_margin > recv_max_margin)) + recv_max_margin = recv_margin; + else + continue; + + *brr = br; + *srr = sr - 1; + *cks = c; } } @@ -1834,10 +1874,19 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, { struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg; - unsigned int baud, smr_val, max_baud, cks = 0; + unsigned int baud, smr_val = 0, max_baud, cks = 0; int t = -1; unsigned int srr = 15; + if ((termios->c_cflag & CSIZE) == CS7) + smr_val |= SCSMR_CHR; + if (termios->c_cflag & PARENB) + smr_val |= SCSMR_PE; + if (termios->c_cflag & PARODD) + smr_val |= SCSMR_PE | SCSMR_ODD; + if (termios->c_cflag & CSTOPB) + smr_val |= SCSMR_STOP; + /* * earlyprintk comes here early on with port->uartclk set to zero. * the clock framework is not up and running at this point so here @@ -1851,8 +1900,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, max_baud); if (likely(baud && port->uartclk)) { if (s->cfg->type == PORT_HSCIF) { + int frame_len = sci_baud_calc_frame_len(smr_val); sci_baud_calc_hscif(baud, port->uartclk, &t, &srr, - &cks); + &cks, frame_len); } else { t = sci_scbrr_calc(s, baud, port->uartclk); for (cks = 0; t >= 256 && cks <= 3; cks++) @@ -1864,16 +1914,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_reset(port); - smr_val = serial_port_in(port, SCSMR) & 3; - - if ((termios->c_cflag & CSIZE) == CS7) - smr_val |= SCSMR_CHR; - if (termios->c_cflag & PARENB) - smr_val |= SCSMR_PE; - if (termios->c_cflag & PARODD) - smr_val |= SCSMR_PE | SCSMR_ODD; - if (termios->c_cflag & CSTOPB) - smr_val |= SCSMR_STOP; + smr_val |= serial_port_in(port, SCSMR) & 3; uart_update_timeout(port, termios->c_cflag, baud); From 876496b8cd01b02f7eb561c27aeaf908e4c3f86e Mon Sep 17 00:00:00 2001 From: Jingchang Lu Date: Mon, 14 Jul 2014 17:41:10 +0800 Subject: [PATCH 59/82] dt-binding: fsl-lpuart: use exact SoC revision to document binding use exact SoC revision instead of wildcard describing to make the binding more clearer. Signed-off-by: Jingchang Lu Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/fsl-lpuart.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt index a1d1205d8185..c95005efbcb8 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt @@ -1,7 +1,11 @@ * Freescale low power universal asynchronous receiver/transmitter (lpuart) Required properties: -- compatible : Should be "fsl,-lpuart" +- compatible : + - "fsl,vf610-lpuart" for lpuart compatible with the one integrated + on Vybrid vf610 SoC with 8-bit register organization + - "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated + on LS1021A SoC with 32-bit big-endian register organization - reg : Address and length of the register set for the device - interrupts : Should contain uart interrupt - clocks : phandle + clock specifier pairs, one for each entry in clock-names From 380c966c093e7239e42a81f165b20b2bad2658bc Mon Sep 17 00:00:00 2001 From: Jingchang Lu Date: Mon, 14 Jul 2014 17:41:11 +0800 Subject: [PATCH 60/82] tty: serial: fsl_lpuart: add 32-bit register interface support This add the 32-bit register version LPUART support with big-endian byte order. Signed-off-by: Jingchang Lu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 645 +++++++++++++++++++++++++++++++- 1 file changed, 637 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index acd3617677e8..6dd53af546a3 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1,7 +1,7 @@ /* * Freescale lpuart serial port driver * - * Copyright 2012-2013 Freescale Semiconductor, Inc. + * Copyright 2012-2014 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -117,6 +117,113 @@ #define UARTSFIFO_TXOF 0x02 #define UARTSFIFO_RXUF 0x01 +/* 32-bit register defination */ +#define UARTBAUD 0x00 +#define UARTSTAT 0x04 +#define UARTCTRL 0x08 +#define UARTDATA 0x0C +#define UARTMATCH 0x10 +#define UARTMODIR 0x14 +#define UARTFIFO 0x18 +#define UARTWATER 0x1c + +#define UARTBAUD_MAEN1 0x80000000 +#define UARTBAUD_MAEN2 0x40000000 +#define UARTBAUD_M10 0x20000000 +#define UARTBAUD_TDMAE 0x00800000 +#define UARTBAUD_RDMAE 0x00200000 +#define UARTBAUD_MATCFG 0x00400000 +#define UARTBAUD_BOTHEDGE 0x00020000 +#define UARTBAUD_RESYNCDIS 0x00010000 +#define UARTBAUD_LBKDIE 0x00008000 +#define UARTBAUD_RXEDGIE 0x00004000 +#define UARTBAUD_SBNS 0x00002000 +#define UARTBAUD_SBR 0x00000000 +#define UARTBAUD_SBR_MASK 0x1fff + +#define UARTSTAT_LBKDIF 0x80000000 +#define UARTSTAT_RXEDGIF 0x40000000 +#define UARTSTAT_MSBF 0x20000000 +#define UARTSTAT_RXINV 0x10000000 +#define UARTSTAT_RWUID 0x08000000 +#define UARTSTAT_BRK13 0x04000000 +#define UARTSTAT_LBKDE 0x02000000 +#define UARTSTAT_RAF 0x01000000 +#define UARTSTAT_TDRE 0x00800000 +#define UARTSTAT_TC 0x00400000 +#define UARTSTAT_RDRF 0x00200000 +#define UARTSTAT_IDLE 0x00100000 +#define UARTSTAT_OR 0x00080000 +#define UARTSTAT_NF 0x00040000 +#define UARTSTAT_FE 0x00020000 +#define UARTSTAT_PE 0x00010000 +#define UARTSTAT_MA1F 0x00008000 +#define UARTSTAT_M21F 0x00004000 + +#define UARTCTRL_R8T9 0x80000000 +#define UARTCTRL_R9T8 0x40000000 +#define UARTCTRL_TXDIR 0x20000000 +#define UARTCTRL_TXINV 0x10000000 +#define UARTCTRL_ORIE 0x08000000 +#define UARTCTRL_NEIE 0x04000000 +#define UARTCTRL_FEIE 0x02000000 +#define UARTCTRL_PEIE 0x01000000 +#define UARTCTRL_TIE 0x00800000 +#define UARTCTRL_TCIE 0x00400000 +#define UARTCTRL_RIE 0x00200000 +#define UARTCTRL_ILIE 0x00100000 +#define UARTCTRL_TE 0x00080000 +#define UARTCTRL_RE 0x00040000 +#define UARTCTRL_RWU 0x00020000 +#define UARTCTRL_SBK 0x00010000 +#define UARTCTRL_MA1IE 0x00008000 +#define UARTCTRL_MA2IE 0x00004000 +#define UARTCTRL_IDLECFG 0x00000100 +#define UARTCTRL_LOOPS 0x00000080 +#define UARTCTRL_DOZEEN 0x00000040 +#define UARTCTRL_RSRC 0x00000020 +#define UARTCTRL_M 0x00000010 +#define UARTCTRL_WAKE 0x00000008 +#define UARTCTRL_ILT 0x00000004 +#define UARTCTRL_PE 0x00000002 +#define UARTCTRL_PT 0x00000001 + +#define UARTDATA_NOISY 0x00008000 +#define UARTDATA_PARITYE 0x00004000 +#define UARTDATA_FRETSC 0x00002000 +#define UARTDATA_RXEMPT 0x00001000 +#define UARTDATA_IDLINE 0x00000800 +#define UARTDATA_MASK 0x3ff + +#define UARTMODIR_IREN 0x00020000 +#define UARTMODIR_TXCTSSRC 0x00000020 +#define UARTMODIR_TXCTSC 0x00000010 +#define UARTMODIR_RXRTSE 0x00000008 +#define UARTMODIR_TXRTSPOL 0x00000004 +#define UARTMODIR_TXRTSE 0x00000002 +#define UARTMODIR_TXCTSE 0x00000001 + +#define UARTFIFO_TXEMPT 0x00800000 +#define UARTFIFO_RXEMPT 0x00400000 +#define UARTFIFO_TXOF 0x00020000 +#define UARTFIFO_RXUF 0x00010000 +#define UARTFIFO_TXFLUSH 0x00008000 +#define UARTFIFO_RXFLUSH 0x00004000 +#define UARTFIFO_TXOFE 0x00000200 +#define UARTFIFO_RXUFE 0x00000100 +#define UARTFIFO_TXFE 0x00000080 +#define UARTFIFO_FIFOSIZE_MASK 0x7 +#define UARTFIFO_TXSIZE_OFF 4 +#define UARTFIFO_RXFE 0x00000008 +#define UARTFIFO_RXSIZE_OFF 0 + +#define UARTWATER_COUNT_MASK 0xff +#define UARTWATER_TXCNT_OFF 8 +#define UARTWATER_RXCNT_OFF 24 +#define UARTWATER_WATER_MASK 0xff +#define UARTWATER_TXWATER_OFF 0 +#define UARTWATER_RXWATER_OFF 16 + #define FSL_UART_RX_DMA_BUFFER_SIZE 64 #define DRIVER_NAME "fsl-lpuart" @@ -128,6 +235,7 @@ struct lpuart_port { struct clk *clk; unsigned int txfifo_size; unsigned int rxfifo_size; + bool lpuart32; bool lpuart_dma_use; struct dma_chan *dma_tx_chan; @@ -152,6 +260,9 @@ static struct of_device_id lpuart_dt_ids[] = { { .compatible = "fsl,vf610-lpuart", }, + { + .compatible = "fsl,ls1021a-lpuart", + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, lpuart_dt_ids); @@ -160,6 +271,16 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids); static void lpuart_dma_tx_complete(void *arg); static void lpuart_dma_rx_complete(void *arg); +static u32 lpuart32_read(void __iomem *addr) +{ + return ioread32be(addr); +} + +static void lpuart32_write(u32 val, void __iomem *addr) +{ + iowrite32be(val, addr); +} + static void lpuart_stop_tx(struct uart_port *port) { unsigned char temp; @@ -169,6 +290,15 @@ static void lpuart_stop_tx(struct uart_port *port) writeb(temp, port->membase + UARTCR2); } +static void lpuart32_stop_tx(struct uart_port *port) +{ + unsigned long temp; + + temp = lpuart32_read(port->membase + UARTCTRL); + temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE); + lpuart32_write(temp, port->membase + UARTCTRL); +} + static void lpuart_stop_rx(struct uart_port *port) { unsigned char temp; @@ -177,6 +307,14 @@ static void lpuart_stop_rx(struct uart_port *port) writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2); } +static void lpuart32_stop_rx(struct uart_port *port) +{ + unsigned long temp; + + temp = lpuart32_read(port->membase + UARTCTRL); + lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL); +} + static void lpuart_copy_rx_to_tty(struct lpuart_port *sport, struct tty_port *tty, int count) { @@ -399,6 +537,30 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport) lpuart_stop_tx(&sport->port); } +static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long txcnt; + + txcnt = lpuart32_read(sport->port.membase + UARTWATER); + txcnt = txcnt >> UARTWATER_TXCNT_OFF; + txcnt &= UARTWATER_COUNT_MASK; + while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) { + lpuart32_write(xmit->buf[xmit->tail], sport->port.membase + UARTDATA); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + txcnt = lpuart32_read(sport->port.membase + UARTWATER); + txcnt = txcnt >> UARTWATER_TXCNT_OFF; + txcnt &= UARTWATER_COUNT_MASK; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (uart_circ_empty(xmit)) + lpuart32_stop_tx(&sport->port); +} + static void lpuart_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, @@ -418,6 +580,18 @@ static void lpuart_start_tx(struct uart_port *port) } } +static void lpuart32_start_tx(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned long temp; + + temp = lpuart32_read(port->membase + UARTCTRL); + lpuart32_write(temp | UARTCTRL_TIE, port->membase + UARTCTRL); + + if (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE) + lpuart32_transmit_buffer(sport); +} + static irqreturn_t lpuart_txint(int irq, void *dev_id) { struct lpuart_port *sport = dev_id; @@ -426,16 +600,25 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id) spin_lock_irqsave(&sport->port.lock, flags); if (sport->port.x_char) { - writeb(sport->port.x_char, sport->port.membase + UARTDR); + if (sport->lpuart32) + lpuart32_write(sport->port.x_char, sport->port.membase + UARTDATA); + else + writeb(sport->port.x_char, sport->port.membase + UARTDR); goto out; } if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - lpuart_stop_tx(&sport->port); + if (sport->lpuart32) + lpuart32_stop_tx(&sport->port); + else + lpuart_stop_tx(&sport->port); goto out; } - lpuart_transmit_buffer(sport); + if (sport->lpuart32) + lpuart32_transmit_buffer(sport); + else + lpuart_transmit_buffer(sport); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); @@ -508,6 +691,70 @@ static irqreturn_t lpuart_rxint(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t lpuart32_rxint(int irq, void *dev_id) +{ + struct lpuart_port *sport = dev_id; + unsigned int flg, ignored = 0; + struct tty_port *port = &sport->port.state->port; + unsigned long flags; + unsigned long rx, sr; + + spin_lock_irqsave(&sport->port.lock, flags); + + while (!(lpuart32_read(sport->port.membase + UARTFIFO) & UARTFIFO_RXEMPT)) { + flg = TTY_NORMAL; + sport->port.icount.rx++; + /* + * to clear the FE, OR, NF, FE, PE flags, + * read STAT then read DATA reg + */ + sr = lpuart32_read(sport->port.membase + UARTSTAT); + rx = lpuart32_read(sport->port.membase + UARTDATA); + rx &= 0x3ff; + + if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) + continue; + + if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) { + if (sr & UARTSTAT_PE) + sport->port.icount.parity++; + else if (sr & UARTSTAT_FE) + sport->port.icount.frame++; + + if (sr & UARTSTAT_OR) + sport->port.icount.overrun++; + + if (sr & sport->port.ignore_status_mask) { + if (++ignored > 100) + goto out; + continue; + } + + sr &= sport->port.read_status_mask; + + if (sr & UARTSTAT_PE) + flg = TTY_PARITY; + else if (sr & UARTSTAT_FE) + flg = TTY_FRAME; + + if (sr & UARTSTAT_OR) + flg = TTY_OVERRUN; + +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } + + tty_insert_flip_char(port, rx, flg); + } + +out: + spin_unlock_irqrestore(&sport->port.lock, flags); + + tty_flip_buffer_push(port); + return IRQ_HANDLED; +} + static irqreturn_t lpuart_int(int irq, void *dev_id) { struct lpuart_port *sport = dev_id; @@ -532,6 +779,26 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t lpuart32_int(int irq, void *dev_id) +{ + struct lpuart_port *sport = dev_id; + unsigned long sts, rxcount; + + sts = lpuart32_read(sport->port.membase + UARTSTAT); + rxcount = lpuart32_read(sport->port.membase + UARTWATER); + rxcount = rxcount >> UARTWATER_RXCNT_OFF; + + if (sts & UARTSTAT_RDRF || rxcount > 0) + lpuart32_rxint(irq, dev_id); + + if ((sts & UARTSTAT_TDRE) && + !(lpuart32_read(sport->port.membase + UARTBAUD) & UARTBAUD_TDMAE)) + lpuart_txint(irq, dev_id); + + lpuart32_write(sts, sport->port.membase + UARTSTAT); + return IRQ_HANDLED; +} + /* return TIOCSER_TEMT when transmitter is not busy */ static unsigned int lpuart_tx_empty(struct uart_port *port) { @@ -539,6 +806,12 @@ static unsigned int lpuart_tx_empty(struct uart_port *port) TIOCSER_TEMT : 0; } +static unsigned int lpuart32_tx_empty(struct uart_port *port) +{ + return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ? + TIOCSER_TEMT : 0; +} + static unsigned int lpuart_get_mctrl(struct uart_port *port) { unsigned int temp = 0; @@ -554,6 +827,21 @@ static unsigned int lpuart_get_mctrl(struct uart_port *port) return temp; } +static unsigned int lpuart32_get_mctrl(struct uart_port *port) +{ + unsigned int temp = 0; + unsigned long reg; + + reg = lpuart32_read(port->membase + UARTMODIR); + if (reg & UARTMODIR_TXCTSE) + temp |= TIOCM_CTS; + + if (reg & UARTMODIR_RXRTSE) + temp |= TIOCM_RTS; + + return temp; +} + static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned char temp; @@ -570,6 +858,22 @@ static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) writeb(temp, port->membase + UARTMODEM); } +static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned long temp; + + temp = lpuart32_read(port->membase + UARTMODIR) & + ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE); + + if (mctrl & TIOCM_RTS) + temp |= UARTMODIR_RXRTSE; + + if (mctrl & TIOCM_CTS) + temp |= UARTMODIR_TXCTSE; + + lpuart32_write(temp, port->membase + UARTMODIR); +} + static void lpuart_break_ctl(struct uart_port *port, int break_state) { unsigned char temp; @@ -582,6 +886,18 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state) writeb(temp, port->membase + UARTCR2); } +static void lpuart32_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long temp; + + temp = lpuart32_read(port->membase + UARTCTRL) & ~UARTCTRL_SBK; + + if (break_state != 0) + temp |= UARTCTRL_SBK; + + lpuart32_write(temp, port->membase + UARTCTRL); +} + static void lpuart_setup_watermark(struct lpuart_port *sport) { unsigned char val, cr2; @@ -608,6 +924,31 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(cr2_saved, sport->port.membase + UARTCR2); } +static void lpuart32_setup_watermark(struct lpuart_port *sport) +{ + unsigned long val, ctrl; + unsigned long ctrl_saved; + + ctrl = lpuart32_read(sport->port.membase + UARTCTRL); + ctrl_saved = ctrl; + ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE | + UARTCTRL_RIE | UARTCTRL_RE); + lpuart32_write(ctrl, sport->port.membase + UARTCTRL); + + /* enable FIFO mode */ + val = lpuart32_read(sport->port.membase + UARTFIFO); + val |= UARTFIFO_TXFE | UARTFIFO_RXFE; + val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; + lpuart32_write(val, sport->port.membase + UARTFIFO); + + /* set the watermark */ + val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF); + lpuart32_write(val, sport->port.membase + UARTWATER); + + /* Restore cr2 */ + lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL); +} + static int lpuart_dma_tx_request(struct uart_port *port) { struct lpuart_port *sport = container_of(port, @@ -786,6 +1127,40 @@ static int lpuart_startup(struct uart_port *port) return 0; } +static int lpuart32_startup(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + int ret; + unsigned long flags; + unsigned long temp; + + /* determine FIFO size */ + temp = lpuart32_read(sport->port.membase + UARTFIFO); + + sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) & + UARTFIFO_FIFOSIZE_MASK) - 1); + + sport->rxfifo_size = 0x1 << (((temp >> UARTFIFO_RXSIZE_OFF) & + UARTFIFO_FIFOSIZE_MASK) - 1); + + ret = devm_request_irq(port->dev, port->irq, lpuart32_int, 0, + DRIVER_NAME, sport); + if (ret) + return ret; + + spin_lock_irqsave(&sport->port.lock, flags); + + lpuart32_setup_watermark(sport); + + temp = lpuart32_read(sport->port.membase + UARTCTRL); + temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE); + temp |= UARTCTRL_ILIE; + lpuart32_write(temp, sport->port.membase + UARTCTRL); + + spin_unlock_irqrestore(&sport->port.lock, flags); + return 0; +} + static void lpuart_shutdown(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); @@ -810,6 +1185,25 @@ static void lpuart_shutdown(struct uart_port *port) } } +static void lpuart32_shutdown(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned long temp; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* disable Rx/Tx and interrupts */ + temp = lpuart32_read(port->membase + UARTCTRL); + temp &= ~(UARTCTRL_TE | UARTCTRL_RE | + UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE); + lpuart32_write(temp, port->membase + UARTCTRL); + + spin_unlock_irqrestore(&port->lock, flags); + + devm_free_irq(port->dev, port->irq, sport); +} + static void lpuart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -947,6 +1341,125 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&sport->port.lock, flags); } +static void +lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned long flags; + unsigned long ctrl, old_ctrl, bd, modem; + unsigned int baud; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + unsigned int sbr; + + ctrl = old_ctrl = lpuart32_read(sport->port.membase + UARTCTRL); + bd = lpuart32_read(sport->port.membase + UARTBAUD); + modem = lpuart32_read(sport->port.membase + UARTMODIR); + /* + * only support CS8 and CS7, and for CS7 must enable PE. + * supported mode: + * - (7,e/o,1) + * - (8,n,1) + * - (8,m/s,1) + * - (8,e/o,1) + */ + while ((termios->c_cflag & CSIZE) != CS8 && + (termios->c_cflag & CSIZE) != CS7) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= old_csize; + old_csize = CS8; + } + + if ((termios->c_cflag & CSIZE) == CS8 || + (termios->c_cflag & CSIZE) == CS7) + ctrl = old_ctrl & ~UARTCTRL_M; + + if (termios->c_cflag & CMSPAR) { + if ((termios->c_cflag & CSIZE) != CS8) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + } + ctrl |= UARTCTRL_M; + } + + if (termios->c_cflag & CRTSCTS) { + modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + } else { + termios->c_cflag &= ~CRTSCTS; + modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + } + + if (termios->c_cflag & CSTOPB) + termios->c_cflag &= ~CSTOPB; + + /* parity must be enabled when CS7 to match 8-bits format */ + if ((termios->c_cflag & CSIZE) == CS7) + termios->c_cflag |= PARENB; + + if ((termios->c_cflag & PARENB)) { + if (termios->c_cflag & CMSPAR) { + ctrl &= ~UARTCTRL_PE; + ctrl |= UARTCTRL_M; + } else { + ctrl |= UARTCR1_PE; + if ((termios->c_cflag & CSIZE) == CS8) + ctrl |= UARTCTRL_M; + if (termios->c_cflag & PARODD) + ctrl |= UARTCTRL_PT; + else + ctrl &= ~UARTCTRL_PT; + } + } + + /* ask the core to calculate the divisor */ + baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->port.read_status_mask = 0; + if (termios->c_iflag & INPCK) + sport->port.read_status_mask |= (UARTSTAT_FE | UARTSTAT_PE); + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) + sport->port.read_status_mask |= UARTSTAT_FE; + + /* characters to ignore */ + sport->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= UARTSTAT_PE; + if (termios->c_iflag & IGNBRK) { + sport->port.ignore_status_mask |= UARTSTAT_FE; + /* + * if we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= UARTSTAT_OR; + } + + /* update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* wait transmit engin complete */ + while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC)) + barrier(); + + /* disable transmit and receive */ + lpuart32_write(old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), + sport->port.membase + UARTCTRL); + + sbr = sport->port.uartclk / (16 * baud); + bd &= ~UARTBAUD_SBR_MASK; + bd |= sbr & UARTBAUD_SBR_MASK; + bd |= UARTBAUD_BOTHEDGE; + bd &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE); + lpuart32_write(bd, sport->port.membase + UARTBAUD); + lpuart32_write(modem, sport->port.membase + UARTMODIR); + lpuart32_write(ctrl, sport->port.membase + UARTCTRL); + /* restore control register */ + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + static const char *lpuart_type(struct uart_port *port) { return "FSL_LPUART"; @@ -1006,6 +1519,24 @@ static struct uart_ops lpuart_pops = { .verify_port = lpuart_verify_port, }; +static struct uart_ops lpuart32_pops = { + .tx_empty = lpuart32_tx_empty, + .set_mctrl = lpuart32_set_mctrl, + .get_mctrl = lpuart32_get_mctrl, + .stop_tx = lpuart32_stop_tx, + .start_tx = lpuart32_start_tx, + .stop_rx = lpuart32_stop_rx, + .break_ctl = lpuart32_break_ctl, + .startup = lpuart32_startup, + .shutdown = lpuart32_shutdown, + .set_termios = lpuart32_set_termios, + .type = lpuart_type, + .request_port = lpuart_request_port, + .release_port = lpuart_release_port, + .config_port = lpuart_config_port, + .verify_port = lpuart_verify_port, +}; + static struct lpuart_port *lpuart_ports[UART_NR]; #ifdef CONFIG_SERIAL_FSL_LPUART_CONSOLE @@ -1017,6 +1548,14 @@ static void lpuart_console_putchar(struct uart_port *port, int ch) writeb(ch, port->membase + UARTDR); } +static void lpuart32_console_putchar(struct uart_port *port, int ch) +{ + while (!(lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE)) + barrier(); + + lpuart32_write(ch, port->membase + UARTDATA); +} + static void lpuart_console_write(struct console *co, const char *s, unsigned int count) { @@ -1038,6 +1577,27 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) writeb(old_cr2, sport->port.membase + UARTCR2); } +static void +lpuart32_console_write(struct console *co, const char *s, unsigned int count) +{ + struct lpuart_port *sport = lpuart_ports[co->index]; + unsigned long old_cr, cr; + + /* first save CR2 and then disable interrupts */ + cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL); + cr |= (UARTCTRL_TE | UARTCTRL_RE); + cr &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE); + lpuart32_write(cr, sport->port.membase + UARTCTRL); + + uart_console_write(&sport->port, s, count, lpuart32_console_putchar); + + /* wait for transmitter finish complete and restore CR2 */ + while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC)) + barrier(); + + lpuart32_write(old_cr, sport->port.membase + UARTCTRL); +} + /* * if the port was already initialised (eg, by a boot loader), * try to determine the current setup. @@ -1091,6 +1651,49 @@ lpuart_console_get_options(struct lpuart_port *sport, int *baud, "from %d to %d\n", baud_raw, *baud); } +static void __init +lpuart32_console_get_options(struct lpuart_port *sport, int *baud, + int *parity, int *bits) +{ + unsigned long cr, bd; + unsigned int sbr, uartclk, baud_raw; + + cr = lpuart32_read(sport->port.membase + UARTCTRL); + cr &= UARTCTRL_TE | UARTCTRL_RE; + if (!cr) + return; + + /* ok, the port was enabled */ + + cr = lpuart32_read(sport->port.membase + UARTCTRL); + + *parity = 'n'; + if (cr & UARTCTRL_PE) { + if (cr & UARTCTRL_PT) + *parity = 'o'; + else + *parity = 'e'; + } + + if (cr & UARTCTRL_M) + *bits = 9; + else + *bits = 8; + + bd = lpuart32_read(sport->port.membase + UARTBAUD); + bd &= UARTBAUD_SBR_MASK; + sbr = bd; + uartclk = clk_get_rate(sport->clk); + /* + * baud = mod_clk/(16*(sbr[13]+(brfa)/32) + */ + baud_raw = uartclk / (16 * sbr); + + if (*baud != baud_raw) + printk(KERN_INFO "Serial: Console lpuart rounded baud rate" + "from %d to %d\n", baud_raw, *baud); +} + static int __init lpuart_console_setup(struct console *co, char *options) { struct lpuart_port *sport; @@ -1114,9 +1717,15 @@ static int __init lpuart_console_setup(struct console *co, char *options) if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else - lpuart_console_get_options(sport, &baud, &parity, &bits); + if (sport->lpuart32) + lpuart32_console_get_options(sport, &baud, &parity, &bits); + else + lpuart_console_get_options(sport, &baud, &parity, &bits); - lpuart_setup_watermark(sport); + if (sport->lpuart32) + lpuart32_setup_watermark(sport); + else + lpuart_setup_watermark(sport); return uart_set_options(&sport->port, co, baud, parity, bits, flow); } @@ -1132,9 +1741,21 @@ static struct console lpuart_console = { .data = &lpuart_reg, }; +static struct console lpuart32_console = { + .name = DEV_NAME, + .write = lpuart32_console_write, + .device = uart_console_device, + .setup = lpuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lpuart_reg, +}; + #define LPUART_CONSOLE (&lpuart_console) +#define LPUART32_CONSOLE (&lpuart32_console) #else #define LPUART_CONSOLE NULL +#define LPUART32_CONSOLE NULL #endif static struct uart_driver lpuart_reg = { @@ -1164,7 +1785,7 @@ static int lpuart_probe(struct platform_device *pdev) return ret; } sport->port.line = ret; - + sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; @@ -1178,7 +1799,10 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.type = PORT_LPUART; sport->port.iotype = UPIO_MEM; sport->port.irq = platform_get_irq(pdev, 0); - sport->port.ops = &lpuart_pops; + if (sport->lpuart32) + sport->port.ops = &lpuart32_pops; + else + sport->port.ops = &lpuart_pops; sport->port.flags = UPF_BOOT_AUTOCONF; sport->clk = devm_clk_get(&pdev->dev, "ipg"); @@ -1200,6 +1824,11 @@ static int lpuart_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &sport->port); + if (sport->lpuart32) + lpuart_reg.cons = LPUART32_CONSOLE; + else + lpuart_reg.cons = LPUART_CONSOLE; + ret = uart_add_one_port(&lpuart_reg, &sport->port); if (ret) { clk_disable_unprepare(sport->clk); From b1261c86fe238cc0da3f5dc837a38a0c39f3e7c4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 14 Jul 2014 14:26:14 +0300 Subject: [PATCH 61/82] serial: 8250: introduce up_to_u8250p() helper It helps to cast struct uart_port to struct uart_8250_port at runtime. Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 57 ++++++++++------------------- drivers/tty/serial/8250/8250_dw.c | 8 ++-- drivers/tty/serial/8250/8250_fsl.c | 3 +- drivers/tty/serial/8250/8250_pci.c | 6 +-- include/linux/serial_8250.h | 5 +++ 5 files changed, 32 insertions(+), 47 deletions(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 7a91c6d1eb7d..0da01458816e 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -439,8 +439,7 @@ static int exar_handle_irq(struct uart_port *port); static void set_io_from_upio(struct uart_port *p) { - struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(p); up->dl_read = default_serial_dl_read; up->dl_write = default_serial_dl_write; @@ -1277,8 +1276,7 @@ static inline void __stop_tx(struct uart_8250_port *p) static void serial8250_stop_tx(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); __stop_tx(up); @@ -1293,8 +1291,7 @@ static void serial8250_stop_tx(struct uart_port *port) static void serial8250_start_tx(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); if (up->dma && !serial8250_tx_dma(up)) { return; @@ -1322,8 +1319,7 @@ static void serial8250_start_tx(struct uart_port *port) static void serial8250_stop_rx(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; @@ -1332,8 +1328,7 @@ static void serial8250_stop_rx(struct uart_port *port) static void serial8250_enable_ms(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); /* no MSR capabilities */ if (up->bugs & UART_BUG_NOMSR) @@ -1499,8 +1494,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) { unsigned char status; unsigned long flags; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); int dma_err = 0; if (iir & UART_IIR_NO_INT) @@ -1785,8 +1779,7 @@ static void serial8250_backup_timeout(unsigned long data) static unsigned int serial8250_tx_empty(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; unsigned int lsr; @@ -1800,8 +1793,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) static unsigned int serial8250_get_mctrl(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); unsigned int status; unsigned int ret; @@ -1821,8 +1813,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port) static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); unsigned char mcr = 0; if (mctrl & TIOCM_RTS) @@ -1843,8 +1834,7 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) static void serial8250_break_ctl(struct uart_port *port, int break_state) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -1911,8 +1901,7 @@ static void serial8250_put_poll_char(struct uart_port *port, unsigned char c) { unsigned int ier; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); /* * First save the IER then disable the interrupts @@ -1941,8 +1930,7 @@ static void serial8250_put_poll_char(struct uart_port *port, static int serial8250_startup(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; unsigned char lsr, iir; int retval; @@ -2194,8 +2182,7 @@ static int serial8250_startup(struct uart_port *port) static void serial8250_shutdown(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; /* @@ -2268,8 +2255,7 @@ void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); unsigned char cval, fcr = 0; unsigned long flags; unsigned int baud, quot; @@ -2498,8 +2484,7 @@ serial8250_set_ldisc(struct uart_port *port, int new) void serial8250_do_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uart_8250_port *p = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *p = up_to_u8250p(port); serial8250_set_sleep(p, state != 0); } @@ -2630,8 +2615,7 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up) static void serial8250_release_port(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); serial8250_release_std_resource(up); if (port->type == PORT_RSA) @@ -2640,8 +2624,7 @@ static void serial8250_release_port(struct uart_port *port) static int serial8250_request_port(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); int ret; if (port->type == PORT_8250_CIR) @@ -2659,8 +2642,7 @@ static int serial8250_request_port(struct uart_port *port) static void serial8250_config_port(struct uart_port *port, int flags) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); int probeflags = PROBE_ANY; int ret; @@ -2859,8 +2841,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) static void serial8250_console_putchar(struct uart_port *port, int ch) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); wait_for_xmitr(up, UART_LSR_THRE); serial_port_out(port, UART_TX, ch); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index c531fa42f838..affdcb192aed 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -84,8 +84,9 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) static void dw8250_force_idle(struct uart_port *p) { - serial8250_clear_and_reinit_fifos(container_of - (p, struct uart_8250_port, port)); + struct uart_8250_port *up = up_to_u8250p(p); + + serial8250_clear_and_reinit_fifos(up); (void)p->serial_in(p, UART_RX); } @@ -255,6 +256,7 @@ static int dw8250_probe_of(struct uart_port *p, struct dw8250_data *data) { struct device_node *np = p->dev->of_node; + struct uart_8250_port *up = up_to_u8250p(p); u32 val; bool has_ucv = true; @@ -287,7 +289,7 @@ static int dw8250_probe_of(struct uart_port *p, } } if (has_ucv) - dw8250_setup_port(container_of(p, struct uart_8250_port, port)); + dw8250_setup_port(up); if (!of_property_read_u32(np, "reg-shift", &val)) p->regshift = val; diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index f4d3c47b88e8..c0533a57ec53 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -28,8 +28,7 @@ int fsl8250_handle_irq(struct uart_port *port) unsigned char lsr, orig_lsr; unsigned long flags; unsigned int iir; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); spin_lock_irqsave(&up->port.lock, flags); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 33137b3ba94d..61830b1792eb 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1581,8 +1581,7 @@ static int skip_tx_en_setup(struct serial_private *priv, static void kt_handle_break(struct uart_port *p) { - struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(p); /* * On receipt of a BI, serial device in Intel ME (Intel * management engine) needs to have its fifos cleared for sane @@ -1593,8 +1592,7 @@ static void kt_handle_break(struct uart_port *p) static unsigned int kt_serial_in(struct uart_port *p, int offset) { - struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(p); unsigned int val; /* diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index af47a8af6024..730ab4b3d686 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -100,6 +100,11 @@ struct uart_8250_port { void (*dl_write)(struct uart_8250_port *, int); }; +static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up) +{ + return container_of(up, struct uart_8250_port, port); +} + int serial8250_register_8250_port(struct uart_8250_port *); void serial8250_unregister_port(int line); void serial8250_suspend_port(int line); From 135f07c3252dc77d0245714d0b413ecc711cd823 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Chatradhi Date: Mon, 14 Jul 2014 17:07:16 +0530 Subject: [PATCH 62/82] serial: samsung: get fifosize via device tree UART modules on some SoCs only differ in the fifosize of each UART channel. Its useless to duplicate the drv_data structure or create a compatible name for such a change. We can get fifosize via the device tree nodes (not mandating it). Also updates the documentation. Signed-off-by: Naveen Krishna Chatradhi Reviewed-by: Tomasz Figa Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/samsung_uart.txt | 4 ++++ drivers/tty/serial/samsung.c | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.txt b/Documentation/devicetree/bindings/serial/samsung_uart.txt index 85e8ee2a17fc..e85f37ec33f0 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.txt +++ b/Documentation/devicetree/bindings/serial/samsung_uart.txt @@ -29,6 +29,9 @@ Required properties: [1] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt [2] Documentation/devicetree/bindings/clock/clock-bindings.txt +Optional properties: +- samsung,uart-fifosize: The fifo size supported by the UART channel + Note: Each Samsung UART should have an alias correctly numbered in the "aliases" node, according to serialN format, where N is the port number (non-negative decimal integer) as specified by User's Manual of respective @@ -51,4 +54,5 @@ Example: "clk_uart_baud3"; clocks = <&clocks PCLK_UART1>, <&clocks PCLK_UART1>, <&clocks SCLK_UART>; + samsung,uart-fifosize = <16>; }; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 6be852d4df6d..e49a9451976e 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1295,9 +1295,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; - ourport->port.fifosize = (ourport->info->fifosize) ? - ourport->info->fifosize : - ourport->drv_data->fifosize[index]; + if (pdev->dev.of_node) + of_property_read_u32(pdev->dev.of_node, + "samsung,uart-fifosize", &ourport->port.fifosize); + + if (!ourport->port.fifosize) { + ourport->port.fifosize = (ourport->info->fifosize) ? + ourport->info->fifosize : + ourport->drv_data->fifosize[index]; + } probe_index++; From 3bcce591aa1f5d9248666e41d99e76c27de6900f Mon Sep 17 00:00:00 2001 From: Naveen Krishna Chatradhi Date: Mon, 14 Jul 2014 17:07:17 +0530 Subject: [PATCH 63/82] serial: samsung: correct the case and default order in switch The cases should comes before default in a switch. Even if we want the case and default to share same code. Its good to define the case first followed by default. Signed-off-by: Naveen Krishna Chatradhi Reviewed-by: Tomasz Figa Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index e49a9451976e..d98f93db85f9 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1542,8 +1542,8 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud, case S3C2410_LCON_CS7: *bits = 7; break; - default: case S3C2410_LCON_CS8: + default: *bits = 8; break; } From 4622eb687374ff042c79211d46bbd107c02f27d8 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Chatradhi Date: Mon, 14 Jul 2014 17:07:18 +0530 Subject: [PATCH 64/82] serial: samsung: improve code clarity by defining a variable The of_node is derived from pdev for every usage, define a device_node variable instead. Signed-off-by: Naveen Krishna Chatradhi Reviewed-by: Tomasz Figa Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index d98f93db85f9..4aff02d6712e 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1269,12 +1269,13 @@ static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data( static int s3c24xx_serial_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct s3c24xx_uart_port *ourport; int index = probe_index; int ret; - if (pdev->dev.of_node) { - ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (np) { + ret = of_alias_get_id(np, "serial"); if (ret >= 0) index = ret; } @@ -1295,8 +1296,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; - if (pdev->dev.of_node) - of_property_read_u32(pdev->dev.of_node, + if (np) + of_property_read_u32(np, "samsung,uart-fifosize", &ourport->port.fifosize); if (!ourport->port.fifosize) { From 3d1c90d48cbe335a47a6a5a05ff731a86eacf6fb Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 15 Jul 2014 17:26:48 +0200 Subject: [PATCH 65/82] serial: altera_jtaguart: Adpot uart_console_write() Follow commit 2970b7f5ea3c ("serial: altera: Adopt uart_console_write()") and don't open code the LF to LFCR conversion in altera_jtaguart either. Use uart_console_write() instead. Signed-off-by: Tobias Klauser Reviewed-by: Daniel Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/altera_jtaguart.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index e7d1aaf07294..afe2e75695e7 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -304,7 +304,7 @@ static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS]; #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS) -static void altera_jtaguart_console_putc(struct console *co, const char c) +static void altera_jtaguart_console_putc(struct console *co, int c) { struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; unsigned long status; @@ -325,7 +325,7 @@ static void altera_jtaguart_console_putc(struct console *co, const char c) spin_unlock_irqrestore(&port->lock, flags); } #else -static void altera_jtaguart_console_putc(struct console *co, const char c) +static void altera_jtaguart_console_putc(struct console *co, int c) { struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; unsigned long flags; @@ -345,11 +345,9 @@ static void altera_jtaguart_console_putc(struct console *co, const char c) static void altera_jtaguart_console_write(struct console *co, const char *s, unsigned int count) { - for (; count; count--, s++) { - altera_jtaguart_console_putc(co, *s); - if (*s == '\n') - altera_jtaguart_console_putc(co, '\r'); - } + struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; + + uart_console_write(port, s, count, altera_jtaguart_console_putc); } static int __init altera_jtaguart_console_setup(struct console *co, From c8b29f049eb2645dd21e40a6613c09f15c731650 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Wed, 16 Jul 2014 14:30:13 +0100 Subject: [PATCH 66/82] tty: kgdb_nmi: Automatically manage tty enable At present it is not possible to boot with the ttyNMI0 console treating character input normally, instead character input triggers a prompt telling the user how to trigger the knock detector and enter the debugger. To use the console normally requires that kdb be entered and the nmi_console command be used to enable the console (or if only kgdb is present then gdb must directly manipulate the value of kgdb_nmi_tty_enabled). This patch automates the management of kgdb_nmi_tty_enabled by keeping track of the number of file handles that are open for reading and using that to determine how to tty should operate. The approach means that: 1. Behaviour before init starts is unchanged. 2. If the userspace runs a getty or some other interactive process on /dev/console (or explicitly on /dev/ttyNMI0) the tty will treat character input like any other tty. 3. If the userspace doesn't use /dev/console or if it uses /dev/console only to log messages (O_WRONLY) then the user prompt is retained. Signed-off-by: Daniel Thompson Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Cc: Jason Wessel Cc: kgdb-bugreport@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/kgdb_nmi.c | 36 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index cfadf2971b12..6ec7501b464d 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -42,7 +42,7 @@ static char *kgdb_nmi_magic = "$3#33"; module_param_named(magic, kgdb_nmi_magic, charp, 0600); MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)"); -static bool kgdb_nmi_tty_enabled; +static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0); static int kgdb_nmi_console_setup(struct console *co, char *options) { @@ -136,7 +136,7 @@ static int kgdb_nmi_poll_one_knock(void) n = 0; } - if (kgdb_nmi_tty_enabled) { + if (atomic_read(&kgdb_nmi_num_readers)) { kgdb_tty_recv(c); return 0; } @@ -197,7 +197,8 @@ static void kgdb_nmi_tty_receiver(unsigned long data) priv->timer.expires = jiffies + (HZ/100); add_timer(&priv->timer); - if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo))) + if (likely(!atomic_read(&kgdb_nmi_num_readers) || + !kfifo_len(&priv->fifo))) return; while (kfifo_out(&priv->fifo, &ch, 1)) @@ -270,13 +271,23 @@ static void kgdb_nmi_tty_cleanup(struct tty_struct *tty) static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file) { struct kgdb_nmi_tty_priv *priv = tty->driver_data; + unsigned int mode = file->f_flags & O_ACCMODE; + int ret; - return tty_port_open(&priv->port, tty, file); + ret = tty_port_open(&priv->port, tty, file); + if (!ret && (mode == O_RDONLY || mode == O_RDWR)) + atomic_inc(&kgdb_nmi_num_readers); + + return ret; } static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file) { struct kgdb_nmi_tty_priv *priv = tty->driver_data; + unsigned int mode = file->f_flags & O_ACCMODE; + + if (mode == O_RDONLY || mode == O_RDWR) + atomic_dec(&kgdb_nmi_num_readers); tty_port_close(&priv->port, tty, file); } @@ -313,12 +324,6 @@ static const struct tty_operations kgdb_nmi_tty_ops = { .write = kgdb_nmi_tty_write, }; -static int kgdb_nmi_enable_console(int argc, const char *argv[]) -{ - kgdb_nmi_tty_enabled = !(argc == 1 && !strcmp(argv[1], "off")); - return 0; -} - int kgdb_register_nmi_console(void) { int ret; @@ -348,19 +353,10 @@ int kgdb_register_nmi_console(void) goto err_drv_reg; } - ret = kdb_register("nmi_console", kgdb_nmi_enable_console, "[off]", - "switch to Linux NMI console", 0); - if (ret) { - pr_err("%s: can't register kdb command: %d\n", __func__, ret); - goto err_kdb_reg; - } - register_console(&kgdb_nmi_console); arch_kgdb_ops.enable_nmi(1); return 0; -err_kdb_reg: - tty_unregister_driver(kgdb_nmi_tty_driver); err_drv_reg: put_tty_driver(kgdb_nmi_tty_driver); return ret; @@ -375,8 +371,6 @@ int kgdb_unregister_nmi_console(void) return 0; arch_kgdb_ops.enable_nmi(0); - kdb_unregister("nmi_console"); - ret = unregister_console(&kgdb_nmi_console); if (ret) return ret; From 266dcff03eed0050b6af11aaf2a61ab837d7ba3f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 16 Jul 2014 01:19:34 +0000 Subject: [PATCH 67/82] Serial: allow port drivers to have a default attribute group Some serial drivers (like 8250), want to add sysfs files. We need to do so in a race-free way, so allow any port to be able to specify an attribute group that should be added at device creation time. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yoshihiro YUNOMAE Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 24 +++++++++++++++++------- include/linux/serial_core.h | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index b70095e55df6..61529a84c3fc 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2564,12 +2564,6 @@ static const struct attribute_group tty_dev_attr_group = { .attrs = tty_dev_attrs, }; -static const struct attribute_group *tty_dev_attr_groups[] = { - &tty_dev_attr_group, - NULL - }; - - /** * uart_add_one_port - attach a driver-defined port structure * @drv: pointer to the uart low level driver structure for this port @@ -2586,6 +2580,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) struct tty_port *port; int ret = 0; struct device *tty_dev; + int num_groups; BUG_ON(in_interrupt()); @@ -2619,12 +2614,26 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) uart_configure_port(drv, state, uport); + num_groups = 2; + if (uport->attr_group) + num_groups++; + + uport->tty_groups = kcalloc(num_groups, sizeof(**uport->tty_groups), + GFP_KERNEL); + if (!uport->tty_groups) { + ret = -ENOMEM; + goto out; + } + uport->tty_groups[0] = &tty_dev_attr_group; + if (uport->attr_group) + uport->tty_groups[1] = uport->attr_group; + /* * Register the port whether it's detected or not. This allows * setserial to be used to alter this port's parameters. */ tty_dev = tty_port_register_device_attr(port, drv->tty_driver, - uport->line, uport->dev, port, tty_dev_attr_groups); + uport->line, uport->dev, port, uport->tty_groups); if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { @@ -2703,6 +2712,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) */ if (uport->type != PORT_UNKNOWN) uport->ops->release_port(uport); + kfree(uport->tty_groups); /* * Indicate that there isn't a port here anymore. diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 5bbb809ee197..cf3a1e789bf5 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -199,6 +199,8 @@ struct uart_port { unsigned char suspended; unsigned char irq_wake; unsigned char unused[2]; + struct attribute_group *attr_group; /* port specific attributes */ + const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ void *private_data; /* generic platform data pointer */ }; From aef9a7bd9b676f797dd5cefd43deb30d36b976a9 Mon Sep 17 00:00:00 2001 From: Yoshihiro YUNOMAE Date: Wed, 16 Jul 2014 01:19:36 +0000 Subject: [PATCH 68/82] serial/uart/8250: Add tunable RX interrupt trigger I/F of FIFO buffers Add tunable RX interrupt trigger I/F of FIFO buffers. Serial devices are used as not only message communication devices but control or sending communication devices. For the latter uses, normally small data will be exchanged, so user applications want to receive data unit as soon as possible for real-time tendency. If we have a sensor which sends a 1 byte data each time and must control a device based on the sensor feedback, the RX interrupt should be triggered for each data. According to HW specification of serial UART devices, RX interrupt trigger can be changed, but the trigger is hard-coded. For example, RX interrupt trigger in 16550A can be set to 1, 4, 8, or 14 bytes for HW, but current driver sets the trigger to only 8bytes. This patch makes some devices change RX interrupt trigger from userland. - Read current setting # cat /sys/class/tty/ttyS0/rx_trig_bytes 8 - Write user setting # echo 1 > /sys/class/tty/ttyS0/rx_trig_bytes # cat /sys/class/tty/ttyS0/rx_trig_bytes 1 - 16550A and Tegra (1, 4, 8, or 14 bytes) - 16650V2 (8, 16, 24, or 28 bytes) - 16654 (8, 16, 56, or 60 bytes) - 16750 (1, 16, 32, or 56 bytes) Changes in V9: - Use attr_group instead of dev_spec_attr_group of uart_port structure Changes in V8: - Divide this patch from V7's patch based on Greg's comment Changes in V7: - Add Documentation - Change I/F name from rx_int_trig to rx_trig_bytes because the name rx_int_trig is hard to understand how users specify the value Changes in V6: - Move FCR_RX_TRIG_* definition in 8250.h to include/uapi/linux/serial_reg.h, rename those to UART_FCR_R_TRIG_*, and use UART_FCR_TRIGGER_MASK to UART_FCR_R_TRIG_BITS() - Change following function names: convert_fcr2val() => fcr_get_rxtrig_bytes() convert_val2rxtrig() => bytes_to_fcr_rxtrig() - Fix typo in serial8250_do_set_termios() - Delete the verbose error message pr_info() in bytes_to_fcr_rxtrig() - Rename *rx_int_trig/rx_trig* to *rxtrig* for several functions or variables (but UI remains rx_int_trig) - Change the meaningless variable name 'val' to 'bytes' following functions: fcr_get_rxtrig_bytes(), bytes_to_fcr_rxtrig(), do_set_rxtrig(), do_serial8250_set_rxtrig(), and serial8250_set_attr_rxtrig() - Use up->fcr in order to get rxtrig_bytes instead of rx_trig_raw in fcr_get_rxtrig_bytes() - Use conf_type->rxtrig_bytes[0] instead of switch statement for support check in register_dev_spec_attr_grp() - Delete the checking whether a user changed FCR or not when minimum buffer is needed in serial8250_do_set_termios() Changes in V5.1: - Fix FCR_RX_TRIG_MAX_STATE definition Changes in V5: - Support Tegra, 16650V2, 16654, and 16750 - Store default FCR value to up->fcr when the port is first created - Add rx_trig_byte[] in uart_config[] for each device and use rx_trig_byte[] in convert_fcr2val() and convert_val2rxtrig() Changes in V4: - Introduce fifo_bug flag in uart_8250_port structure This is enabled only when parity is enabled and UART_BUG_PARITY is enabled for up->bugs. If this flag is enabled, user cannot set RX trigger. - Return -EOPNOTSUPP when it does not support device at convert_fcr2val() and at convert_val2rxtrig() - Set the nearest lower RX trigger when users input a meaningless value at convert_val2rxtrig() - Check whether p->fcr is existing at serial8250_clear_and_reinit_fifos() - Set fcr = up->fcr in the begging of serial8250_do_set_termios() Changes in V3: - Change I/F from ioctl(2) to sysfs(rx_int_trig) Changed in V2: - Use _IOW for TIOCSFIFORTRIG definition - Pass the interrupt trigger value itself Signed-off-by: Yoshihiro YUNOMAE Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-tty | 16 +++ drivers/tty/serial/8250/8250.h | 2 + drivers/tty/serial/8250/8250_core.c | 173 +++++++++++++++++++++++++--- include/linux/serial_8250.h | 2 + include/uapi/linux/serial_reg.h | 5 + 5 files changed, 183 insertions(+), 15 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty index ad22fb0ee765..9eb3c2b6b040 100644 --- a/Documentation/ABI/testing/sysfs-tty +++ b/Documentation/ABI/testing/sysfs-tty @@ -138,3 +138,19 @@ Description: These sysfs values expose the TIOCGSERIAL interface via sysfs rather than via ioctls. + +What: /sys/class/tty/ttyS0/rx_trig_bytes +Date: May 2014 +Contact: Yoshihiro YUNOMAE +Description: + Shows current RX interrupt trigger bytes or sets the + user specified value to change it for the FIFO buffer. + Users can show or set this value regardless of opening the + serial device file or not. + + The RX trigger can be set one of four kinds of values for UART + serials. When users input a meaning less value to this I/F, + the RX trigger is changed to the nearest lower value for the + device specification. For example, when user sets 7bytes on + 16550A, which has 1/4/8/14 bytes trigger, the RX trigger is + automatically changed to 4 bytes. diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 1ebf8538b4fa..1b08c918cd51 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -12,6 +12,7 @@ */ #include +#include #include struct uart_8250_dma { @@ -60,6 +61,7 @@ struct serial8250_config { unsigned short fifo_size; unsigned short tx_loadsz; unsigned char fcr; + unsigned char rxtrig_bytes[UART_FCR_R_TRIG_MAX_STATE]; unsigned int flags; }; diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 0da01458816e..1d42dba6121d 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -161,6 +160,7 @@ static const struct serial8250_config uart_config[] = { .fifo_size = 16, .tx_loadsz = 16, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 4, 8, 14}, .flags = UART_CAP_FIFO, }, [PORT_CIRRUS] = { @@ -180,6 +180,7 @@ static const struct serial8250_config uart_config[] = { .tx_loadsz = 16, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_00, + .rxtrig_bytes = {8, 16, 24, 28}, .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, }, [PORT_16750] = { @@ -188,6 +189,7 @@ static const struct serial8250_config uart_config[] = { .tx_loadsz = 64, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | UART_FCR7_64BYTE, + .rxtrig_bytes = {1, 16, 32, 56}, .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, }, [PORT_STARTECH] = { @@ -209,6 +211,7 @@ static const struct serial8250_config uart_config[] = { .tx_loadsz = 32, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_10, + .rxtrig_bytes = {8, 16, 56, 60}, .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, }, [PORT_16850] = { @@ -266,6 +269,7 @@ static const struct serial8250_config uart_config[] = { .tx_loadsz = 8, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01, + .rxtrig_bytes = {1, 4, 8, 14}, .flags = UART_CAP_FIFO | UART_CAP_RTOIE, }, [PORT_XR17D15X] = { @@ -530,11 +534,8 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) { - unsigned char fcr; - serial8250_clear_fifos(p); - fcr = uart_config[p->port.type].fcr; - serial_out(p, UART_FCR, fcr); + serial_out(p, UART_FCR, p->fcr); } EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); @@ -2256,10 +2257,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned char cval, fcr = 0; + unsigned char cval; unsigned long flags; unsigned int baud, quot; - int fifo_bug = 0; switch (termios->c_cflag & CSIZE) { case CS5: @@ -2282,7 +2282,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_cflag & PARENB) { cval |= UART_LCR_PARITY; if (up->bugs & UART_BUG_PARITY) - fifo_bug = 1; + up->fifo_bug = true; } if (!(termios->c_cflag & PARODD)) cval |= UART_LCR_EPAR; @@ -2306,10 +2306,10 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, quot++; if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { - fcr = uart_config[port->type].fcr; - if ((baud < 2400 && !up->dma) || fifo_bug) { - fcr &= ~UART_FCR_TRIGGER_MASK; - fcr |= UART_FCR_TRIGGER_1; + /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */ + if ((baud < 2400 && !up->dma) || up->fifo_bug) { + up->fcr &= ~UART_FCR_TRIGGER_MASK; + up->fcr |= UART_FCR_TRIGGER_1; } } @@ -2442,15 +2442,15 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * is written without DLAB set, this mode will be disabled. */ if (port->type == PORT_16750) - serial_port_out(port, UART_FCR, fcr); + serial_port_out(port, UART_FCR, up->fcr); serial_port_out(port, UART_LCR, cval); /* reset DLAB */ up->lcr = cval; /* Save LCR */ if (port->type != PORT_16750) { /* emulated UARTs (Lucent Venus 167x) need two steps */ - if (fcr & UART_FCR_ENABLE_FIFO) + if (up->fcr & UART_FCR_ENABLE_FIFO) serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_port_out(port, UART_FCR, fcr); /* set fcr */ + serial_port_out(port, UART_FCR, up->fcr); /* set fcr */ } serial8250_set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags); @@ -2640,6 +2640,146 @@ static int serial8250_request_port(struct uart_port *port) return ret; } +static int fcr_get_rxtrig_bytes(struct uart_8250_port *up) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + unsigned char bytes; + + bytes = conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)]; + + return bytes ? bytes : -EOPNOTSUPP; +} + +static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + int i; + + if (!conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)]) + return -EOPNOTSUPP; + + for (i = 1; i < UART_FCR_R_TRIG_MAX_STATE; i++) { + if (bytes < conf_type->rxtrig_bytes[i]) + /* Use the nearest lower value */ + return (--i) << UART_FCR_R_TRIG_SHIFT; + } + + return UART_FCR_R_TRIG_11; +} + +static int do_get_rxtrig(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = + container_of(uport, struct uart_8250_port, port); + + if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) + return -EINVAL; + + return fcr_get_rxtrig_bytes(up); +} + +static int do_serial8250_get_rxtrig(struct tty_port *port) +{ + int rxtrig_bytes; + + mutex_lock(&port->mutex); + rxtrig_bytes = do_get_rxtrig(port); + mutex_unlock(&port->mutex); + + return rxtrig_bytes; +} + +static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + int rxtrig_bytes; + + rxtrig_bytes = do_serial8250_get_rxtrig(port); + if (rxtrig_bytes < 0) + return rxtrig_bytes; + + return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes); +} + +static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = + container_of(uport, struct uart_8250_port, port); + int rxtrig; + + if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 || + up->fifo_bug) + return -EINVAL; + + rxtrig = bytes_to_fcr_rxtrig(up, bytes); + if (rxtrig < 0) + return rxtrig; + + serial8250_clear_fifos(up); + up->fcr &= ~UART_FCR_TRIGGER_MASK; + up->fcr |= (unsigned char)rxtrig; + serial_out(up, UART_FCR, up->fcr); + return 0; +} + +static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes) +{ + int ret; + + mutex_lock(&port->mutex); + ret = do_set_rxtrig(port, bytes); + mutex_unlock(&port->mutex); + + return ret; +} + +static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + unsigned char bytes; + int ret; + + if (!count) + return -EINVAL; + + ret = kstrtou8(buf, 10, &bytes); + if (ret < 0) + return ret; + + ret = do_serial8250_set_rxtrig(port, bytes); + if (ret < 0) + return ret; + + 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 struct attribute *serial8250_dev_attrs[] = { + &dev_attr_rx_trig_bytes.attr, + 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) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + + if (conf_type->rxtrig_bytes[0]) + up->port.attr_group = &serial8250_dev_attr_group; +} + static void serial8250_config_port(struct uart_port *port, int flags) { struct uart_8250_port *up = up_to_u8250p(port); @@ -2687,6 +2827,9 @@ static void serial8250_config_port(struct uart_port *port, int flags) if ((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) port->handle_irq = exar_handle_irq; + + register_dev_spec_attr_grp(up); + up->fcr = uart_config[up->port.type].fcr; } static int diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 730ab4b3d686..f93649e22c43 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -74,8 +74,10 @@ struct uart_8250_port { struct list_head list; /* ports on this IRQ */ unsigned short capabilities; /* port capabilities */ unsigned short bugs; /* port bugs */ + bool fifo_bug; /* min RX trigger if enabled */ unsigned int tx_loadsz; /* transmit fifo load size */ unsigned char acr; + unsigned char fcr; unsigned char ier; unsigned char lcr; unsigned char mcr; diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h index 99b47058816a..df6c9ab6b0cd 100644 --- a/include/uapi/linux/serial_reg.h +++ b/include/uapi/linux/serial_reg.h @@ -88,6 +88,11 @@ #define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */ #define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode (TI16C750) */ +#define UART_FCR_R_TRIG_SHIFT 6 +#define UART_FCR_R_TRIG_BITS(x) \ + (((x) & UART_FCR_TRIGGER_MASK) >> UART_FCR_R_TRIG_SHIFT) +#define UART_FCR_R_TRIG_MAX_STATE 4 + #define UART_LCR 3 /* Out: Line Control Register */ /* * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting From 2fbe6c5e3e7f8d698d97984a9dce4f05c3d940ed Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 18 Jul 2014 08:50:43 +0200 Subject: [PATCH 69/82] serial: altera_jtaguart: Fix putchar function passed to uart_console_write() Commit 3d1c90d48cbe335a ("serial: altera_jtaguart: Adpot uart_console_write()") introduced the usage of uart_console_write() but didn't change the signature of altera_jtaguart_console_putc() to take a pointer to struct uart_port instead of struct console, breaking the driver's console support and leading to the following warning: > drivers/tty/serial/altera_jtaguart.c: In function 'altera_jtaguart_console_write': > >> drivers/tty/serial/altera_jtaguart.c:350:2: warning: passing argument 4 of 'uart_console_write' from incompatible pointer type [enabled by default] > uart_console_write(port, s, count, altera_jtaguart_console_putc); > ^ > In file included from drivers/tty/serial/altera_jtaguart.c:25:0: > include/linux/serial_core.h:317:6: note: expected 'void (*)(struct uart_port *, int)' but argument is of type 'void (*)(struct console *, int)' > void uart_console_write(struct uart_port *port, const char *s, Fix this by adjusting the signature of altera_jtaguart_console_putc() accordingly. Reported-by: kbuild test robot Reported-by: Greg Kroah-Hartman Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/altera_jtaguart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index afe2e75695e7..d22e3d98ae23 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -304,9 +304,8 @@ static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS]; #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS) -static void altera_jtaguart_console_putc(struct console *co, int c) +static void altera_jtaguart_console_putc(struct uart_port *port, int c) { - struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; unsigned long status; unsigned long flags; @@ -325,9 +324,8 @@ static void altera_jtaguart_console_putc(struct console *co, int c) spin_unlock_irqrestore(&port->lock, flags); } #else -static void altera_jtaguart_console_putc(struct console *co, int c) +static void altera_jtaguart_console_putc(struct uart_port *port, int c) { - struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); From 48479148a2f5311a45867469ae43c983bf3b6c88 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 21 Jul 2014 11:42:04 +0200 Subject: [PATCH 70/82] drivers/tty/serial: use correct type for dma_map/unmap dma_{un}map_* uses 'enum dma_data_direction' not 'enum dma_transfer_direction'. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index c4f750314100..7b63677475c1 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -706,7 +706,7 @@ static void atmel_release_tx_dma(struct uart_port *port) dmaengine_terminate_all(chan); dma_release_channel(chan); dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1, - DMA_MEM_TO_DEV); + DMA_TO_DEVICE); } atmel_port->desc_tx = NULL; @@ -804,7 +804,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) nent = dma_map_sg(port->dev, &atmel_port->sg_tx, 1, - DMA_MEM_TO_DEV); + DMA_TO_DEVICE); if (!nent) { dev_dbg(port->dev, "need to release resource of dma\n"); @@ -883,7 +883,7 @@ static void atmel_release_rx_dma(struct uart_port *port) dmaengine_terminate_all(chan); dma_release_channel(chan); dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1, - DMA_DEV_TO_MEM); + DMA_FROM_DEVICE); } atmel_port->desc_rx = NULL; @@ -968,7 +968,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) nent = dma_map_sg(port->dev, &atmel_port->sg_rx, 1, - DMA_DEV_TO_MEM); + DMA_FROM_DEVICE); if (!nent) { dev_dbg(port->dev, "need to release resource of dma\n"); From c2b703b807e3aba4d2b542c9096c790186a6e71f Mon Sep 17 00:00:00 2001 From: Yoshihiro YUNOMAE Date: Wed, 23 Jul 2014 06:06:22 +0000 Subject: [PATCH 71/82] serial/core: Fix too big allocation for attribute member Current code allocates too much data for tty_groups member of uart_port struct, so fix it. Signed-off-by: Yoshihiro YUNOMAE Reported-by: Dan Carpenter Reviewed-by: Daniel Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 61529a84c3fc..8bb19da01639 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2618,7 +2618,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) if (uport->attr_group) num_groups++; - uport->tty_groups = kcalloc(num_groups, sizeof(**uport->tty_groups), + uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups), GFP_KERNEL); if (!uport->tty_groups) { ret = -ENOMEM; From 850e93eb299dfe9379609d5755068d47b03954f8 Mon Sep 17 00:00:00 2001 From: "xinhui.pan" Date: Wed, 23 Jul 2014 14:31:09 +0800 Subject: [PATCH 72/82] tty/n_gsm.c: get gsm->num after gsm_activate_mux gsm->num is the index of gsm_mux[], it's invalid before calling gsm_activate_mux. Signed-off-by: xinhui.pan Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 2ebe47b78a3e..81e7ccbd9e4a 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2230,8 +2230,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len) static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { - int ret, i; - int base = gsm->num << 6; /* Base for this MUX */ + int ret, i, base; gsm->tty = tty_kref_get(tty); gsm->output = gsmld_output; @@ -2241,6 +2240,7 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) else { /* Don't register device 0 - this is the control channel and not a usable tty interface */ + base = gsm->num << 6; /* Base for this MUX */ for (i = 1; i < NUM_DLCI; i++) tty_register_device(gsm_tty_driver, base + i, NULL); } From af300539def51ef79be3cbc54379f1d86c1733ff Mon Sep 17 00:00:00 2001 From: Kiran Padwal Date: Wed, 23 Jul 2014 15:56:26 +0530 Subject: [PATCH 73/82] tty: serial: msm: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Kiran Padwal Acked-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index c549110509bb..0da0b5474e98 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1065,7 +1065,7 @@ static int msm_serial_remove(struct platform_device *pdev) return 0; } -static struct of_device_id msm_match_table[] = { +static const struct of_device_id msm_match_table[] = { { .compatible = "qcom,msm-uart" }, { .compatible = "qcom,msm-uartdm" }, {} From 5b4e79ae452613a9d391cf1e5ab7e9a49241ad28 Mon Sep 17 00:00:00 2001 From: Maxime COQUELIN Date: Thu, 24 Jul 2014 14:02:55 +0200 Subject: [PATCH 74/82] serial: st-asc: Don't call BUG in asc_console_setup() In order to prevent an asc instance to be used as early console, BUG_ON is used on either mapbase or membase being NULL. Problem is that this condition is also true when we set console to be a ttyASx different to the first asc instance being probed. Instead of calling BUG_ON, it now returns -ENXIO when either mapbase or membase is NULL. Signed-off-by: Maxime Coquelin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/st-asc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 2bee4fbccba1..4e9f4f29f3ce 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -842,7 +842,8 @@ static int asc_console_setup(struct console *co, char *options) * this to be called during the uart port registration when the * driver gets probed and the port should be mapped at that point. */ - BUG_ON(ascport->port.mapbase == 0 || ascport->port.membase == NULL); + if (ascport->port.mapbase == 0 || ascport->port.membase == NULL) + return -ENXIO; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); From 1d6ba284dff546baca58e78546da46be3b48462a Mon Sep 17 00:00:00 2001 From: Maxime COQUELIN Date: Thu, 24 Jul 2014 14:02:56 +0200 Subject: [PATCH 75/82] serial: st-asc: Fix overflow in baudrate calculation In the current calculation, if the required baud rate is above 262143, we get an overflow. This patch uses a 64bits variable to do the maths. Also, we remove the '+1' to avoid a divide by zero if the input clock rate is something unexpected. Indeed, if the input clock rate is zero, it is preferable to be notified, since the UART won't work anyway. Signed-off-by: Maxime Coquelin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/st-asc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 4e9f4f29f3ce..8b2d7356611d 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -527,12 +527,12 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, * ASCBaudRate = ------------------------ * inputclock * - * However to keep the maths inside 32bits we divide top and - * bottom by 64. The +1 is to avoid a divide by zero if the - * input clock rate is something unexpected. + * To keep maths inside 64bits, we divide inputclock by 16. */ - u32 counter = (baud * 16384) / ((port->uartclk / 64) + 1); - asc_out(port, ASC_BAUDRATE, counter); + u64 dividend = (u64)baud * (1 << 16); + + do_div(dividend, port->uartclk / 16); + asc_out(port, ASC_BAUDRATE, dividend); ctrl_val |= ASC_CTL_BAUDMODE; } From 7fe090bf48b522de8cd6fe85e2b3252ed74e74f8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 23 Jul 2014 23:33:06 +0800 Subject: [PATCH 76/82] serial: 8250_dw: Add optional reset control support The Allwinner A31 and A23 SoCs have a reset controller maintaining the UART in reset by default. This patch adds optional reset support to the driver. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/snps-dw-apb-uart.txt | 1 + drivers/tty/serial/8250/8250_dw.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt index 095ac7172ffe..7f76214f728a 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt @@ -15,6 +15,7 @@ The supplying peripheral clock can also be handled, needing a second property Required elements: "baudclk", "apb_pclk" Optional properties: +- resets : phandle to the parent reset controller. - reg-shift : quantity to shift the register offsets by. If this property is not present then the register offsets are not shifted. - reg-io-width : the size (in bytes) of the IO accesses that should be diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index affdcb192aed..501db2f58fd2 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,7 @@ struct dw8250_data { int line; struct clk *clk; struct clk *pclk; + struct reset_control *rst; struct uart_8250_dma dma; }; @@ -383,6 +385,10 @@ static int dw8250_probe(struct platform_device *pdev) } } + data->rst = devm_reset_control_get_optional(&pdev->dev, NULL); + if (!IS_ERR(data->rst)) + reset_control_deassert(data->rst); + data->dma.rx_chan_id = -1; data->dma.tx_chan_id = -1; data->dma.rx_param = data; @@ -426,6 +432,9 @@ static int dw8250_remove(struct platform_device *pdev) serial8250_unregister_port(data->line); + if (!IS_ERR(data->rst)) + reset_control_assert(data->rst); + if (!IS_ERR(data->pclk)) clk_disable_unprepare(data->pclk); From c8ed99d4f6a8ac03f397877d25428698f461a2af Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 23 Jul 2014 23:33:07 +0800 Subject: [PATCH 77/82] serial: 8250_dw: Add support for deferred probing The 8250_dw driver fails to probe if the specified clock isn't registered at probe time. Even if a clock frequency is given, the required clock might be gated because it wasn't properly enabled. This happened to me when the device is registered through DT, and the clock was part of an MFD, the PRCM found on A31 and A23 SoCs. Unlike core clocks that are registered with OF_CLK_DECLARE, which happen almost immediately after the kernel starts, the clocks are registered as sub-devices of the PRCM MFD platform device. Even though devices are registered in the order they are found in the DT, the drivers are registered in a different, arbitrary order. It is possible that the 8250_dw driver is registered, and thus associated with the device and probed, before the clock driver is registered and probed. 8250_dw then reports unable to get the clock, and fails. Without a working console, the kernel panics. This patch adds support for deferred probe handling for the clock and reset controller. It also fixes the cleanup path if serial8250_register_8250_port fails. Signed-off-by: Chen-Yu Tsai Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 41 +++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 501db2f58fd2..4db7987ec225 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -365,8 +365,10 @@ static int dw8250_probe(struct platform_device *pdev) data->usr_reg = DW_UART_USR; data->clk = devm_clk_get(&pdev->dev, "baudclk"); - if (IS_ERR(data->clk)) + if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER) data->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; if (!IS_ERR(data->clk)) { err = clk_prepare_enable(data->clk); if (err) @@ -377,15 +379,23 @@ static int dw8250_probe(struct platform_device *pdev) } data->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); + if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) { + err = -EPROBE_DEFER; + goto err_clk; + } if (!IS_ERR(data->pclk)) { err = clk_prepare_enable(data->pclk); if (err) { dev_err(&pdev->dev, "could not enable apb_pclk\n"); - return err; + goto err_clk; } } data->rst = devm_reset_control_get_optional(&pdev->dev, NULL); + if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) { + err = -EPROBE_DEFER; + goto err_pclk; + } if (!IS_ERR(data->rst)) reset_control_deassert(data->rst); @@ -403,18 +413,21 @@ static int dw8250_probe(struct platform_device *pdev) if (pdev->dev.of_node) { err = dw8250_probe_of(&uart.port, data); if (err) - return err; + goto err_reset; } else if (ACPI_HANDLE(&pdev->dev)) { err = dw8250_probe_acpi(&uart, data); if (err) - return err; + goto err_reset; } else { - return -ENODEV; + err = -ENODEV; + goto err_reset; } data->line = serial8250_register_8250_port(&uart); - if (data->line < 0) - return data->line; + if (data->line < 0) { + err = data->line; + goto err_reset; + } platform_set_drvdata(pdev, data); @@ -422,6 +435,20 @@ static int dw8250_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); return 0; + +err_reset: + if (!IS_ERR(data->rst)) + reset_control_assert(data->rst); + +err_pclk: + if (!IS_ERR(data->pclk)) + clk_disable_unprepare(data->pclk); + +err_clk: + if (!IS_ERR(data->clk)) + clk_disable_unprepare(data->clk); + + return err; } static int dw8250_remove(struct platform_device *pdev) From dc824ebed081ed6227772b3cc5f9c7a6683fb489 Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Fri, 25 Jul 2014 13:53:36 -0400 Subject: [PATCH 78/82] serial: sc16is7xx: Correct initialization of s->clk The s->clk never gets setup in sc16is7xx_probe() and instead was using a local clk variable, but then testing the uninitialized s->clk during teardown Reported-by: Dan Carpenter Signed-off-by: Jon Ringle Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 914825e03427..3284c31085a7 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1060,7 +1060,6 @@ static int sc16is7xx_probe(struct device *dev, struct regmap *regmap, int irq, unsigned long flags) { unsigned long freq, *pfreq = dev_get_platdata(dev); - struct clk *clk; int i, ret; struct sc16is7xx_port *s; @@ -1076,14 +1075,14 @@ static int sc16is7xx_probe(struct device *dev, return -ENOMEM; } - clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) { + s->clk = devm_clk_get(dev, NULL); + if (IS_ERR(s->clk)) { if (pfreq) freq = *pfreq; else - return PTR_ERR(clk); + return PTR_ERR(s->clk); } else { - freq = clk_get_rate(clk); + freq = clk_get_rate(s->clk); } s->regmap = regmap; From 22524b02b17b901f28a62229f8c32416c8e8acfe Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 27 Jul 2014 23:07:11 -0700 Subject: [PATCH 79/82] Revert "ARC: [arcfpga] stdout-path now suffices for earlycon/console" This reverts commit 9da433c0a0b5f71ac92dc9dca778295649675f08. Vineet writes: Could you please revert this single patch from tty-next for 3.17 as the needed core changes are not yet finalized. Cc: Vineet Gupta Cc: Rob Herring Signed-off-by: Greg Kroah-Hartman --- arch/arc/boot/dts/angel4.dts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arc/boot/dts/angel4.dts b/arch/arc/boot/dts/angel4.dts index 298a46daa633..6b57475967a6 100644 --- a/arch/arc/boot/dts/angel4.dts +++ b/arch/arc/boot/dts/angel4.dts @@ -17,8 +17,7 @@ / { interrupt-parent = <&intc>; chosen { - bootargs = "earlycon"; - stdout-path = &arcuart0; + bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8"; }; aliases { From c62fd1d9f094b1a97674374d09869df05cdc1025 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 30 Jul 2014 15:03:57 +0200 Subject: [PATCH 80/82] tty: n_gsm, use setup_timer Just a simple cleanup of init_timer with setting the fields manually. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 81e7ccbd9e4a..d5f578fe3fa6 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2088,9 +2088,7 @@ static int gsm_activate_mux(struct gsm_mux *gsm) struct gsm_dlci *dlci; int i = 0; - init_timer(&gsm->t2_timer); - gsm->t2_timer.function = gsm_control_retransmit; - gsm->t2_timer.data = (unsigned long)gsm; + setup_timer(&gsm->t2_timer, gsm_control_retransmit, (unsigned long)gsm); init_waitqueue_head(&gsm->event); spin_lock_init(&gsm->control_lock); spin_lock_init(&gsm->tx_lock); From 8368d6a2b73900507ad7632b8057532d0c2ee07f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 30 Jul 2014 18:59:52 +0300 Subject: [PATCH 81/82] pch_uart: don't hardcode PCI slot to get DMA device The DMA is a function 0 of the multifunction device where SPI host is attached. Thus, we may avoid to hardcode PCI slot number. Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 2f06e5a71396..ea4ffc2ebb2f 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -736,9 +736,10 @@ static void pch_request_dma(struct uart_port *port) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - dma_dev = pci_get_bus_and_slot(priv->pdev->bus->number, - PCI_DEVFN(0xa, 0)); /* Get DMA's dev - information */ + /* Get DMA's dev information */ + dma_dev = pci_get_slot(priv->pdev->bus, + PCI_DEVFN(PCI_SLOT(priv->pdev->devfn), 0)); + /* Set Tx DMA */ param = &priv->param_tx; param->dma_dev = &dma_dev->dev; From 5a64096700dc9761b57e767c9f0b740eb2cb84dd Mon Sep 17 00:00:00 2001 From: "xinhui.pan" Date: Mon, 28 Jul 2014 16:14:52 +0800 Subject: [PATCH 82/82] tty/n_gsm.c: fix a memory leak in gsmld_open If gsmld_attach_gsm fails, the gsm is not used anymore. tty core will not call gsmld_close to do the cleanup work. tty core just restore to the tty old ldisc. That always causes memory leak. Signed-off-by: xinhui.pan Reported-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index d5f578fe3fa6..152443ab1447 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2366,6 +2366,7 @@ static void gsmld_close(struct tty_struct *tty) static int gsmld_open(struct tty_struct *tty) { struct gsm_mux *gsm; + int ret; if (tty->ops->write == NULL) return -EINVAL; @@ -2380,7 +2381,13 @@ static int gsmld_open(struct tty_struct *tty) /* Attach the initial passive connection */ gsm->encoding = 1; - return gsmld_attach_gsm(tty, gsm); + + ret = gsmld_attach_gsm(tty, gsm); + if (ret != 0) { + gsm_cleanup_mux(gsm); + mux_put(gsm); + } + return ret; } /**