diff options
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/ehv_bytechan.c | 12 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_core.c | 6 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_of.c | 22 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_port.c | 29 | ||||
-rw-r--r-- | drivers/tty/serial/8250/Kconfig | 2 | ||||
-rw-r--r-- | drivers/tty/serial/Kconfig | 1 | ||||
-rw-r--r-- | drivers/tty/serial/atmel_serial.c | 42 | ||||
-rw-r--r-- | drivers/tty/serial/cpm_uart/cpm_uart_core.c | 8 | ||||
-rw-r--r-- | drivers/tty/serial/imx.c | 38 | ||||
-rw-r--r-- | drivers/tty/serial/kgdboc.c | 46 | ||||
-rw-r--r-- | drivers/tty/serial/mxs-auart.c | 3 | ||||
-rw-r--r-- | drivers/tty/serial/pmac_zilog.c | 8 | ||||
-rw-r--r-- | drivers/tty/serial/qcom_geni_serial.c | 69 | ||||
-rw-r--r-- | drivers/tty/serial/samsung.c | 8 | ||||
-rw-r--r-- | drivers/tty/serial/sc16is7xx.c | 47 | ||||
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 63 | ||||
-rw-r--r-- | drivers/tty/serial/sprd_serial.c | 98 | ||||
-rw-r--r-- | drivers/tty/serial/uartlite.c | 71 | ||||
-rw-r--r-- | drivers/tty/serial/xilinx_uartps.c | 299 | ||||
-rw-r--r-- | drivers/tty/tty_buffer.c | 7 | ||||
-rw-r--r-- | drivers/tty/tty_port.c | 7 |
21 files changed, 549 insertions, 337 deletions
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index eea4049b5dcc..769e0a5d1dfc 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -128,8 +128,8 @@ static int find_console_handle(void) */ iprop = of_get_property(np, "hv-handle", NULL); if (!iprop) { - pr_err("ehv-bc: no 'hv-handle' property in %s node\n", - np->name); + pr_err("ehv-bc: no 'hv-handle' property in %pOFn node\n", + np); return 0; } stdout_bc = be32_to_cpu(*iprop); @@ -661,8 +661,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev) iprop = of_get_property(np, "hv-handle", NULL); if (!iprop) { - dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n", - np->name); + dev_err(&pdev->dev, "no 'hv-handle' property in %pOFn node\n", + np); return -ENODEV; } @@ -682,8 +682,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev) bc->rx_irq = irq_of_parse_and_map(np, 0); bc->tx_irq = irq_of_parse_and_map(np, 1); if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) { - dev_err(&pdev->dev, "no 'interrupts' property in %s node\n", - np->name); + dev_err(&pdev->dev, "no 'interrupts' property in %pOFn node\n", + np); ret = -ENODEV; goto error; } diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 8fe3d0ed229e..94f3e1c64490 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -130,12 +130,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) l = l->next; - if (l == i->head && pass_counter++ > PASS_LIMIT) { - /* If we hit this, we're dead. */ - printk_ratelimited(KERN_ERR - "serial8250: too much work for irq%d\n", irq); + if (l == i->head && pass_counter++ > PASS_LIMIT) break; - } } while (l != end); spin_unlock(&i->lock); diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index af8beefe9b5c..877fd7f8a8ed 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -58,7 +58,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, struct resource resource; struct device_node *np = ofdev->dev.of_node; u32 clk, spd, prop; - int ret; + int ret, irq; memset(port, 0, sizeof *port); @@ -143,21 +143,27 @@ static int of_platform_serial_setup(struct platform_device *ofdev, if (ret >= 0) port->line = ret; - port->irq = irq_of_parse_and_map(np, 0); - if (!port->irq) { - ret = -EPROBE_DEFER; - goto err_unprepare; + irq = of_irq_get(np, 0); + if (irq < 0) { + if (irq == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_unprepare; + } + /* IRQ support not mandatory */ + irq = 0; } + port->irq = irq; + info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); if (IS_ERR(info->rst)) { ret = PTR_ERR(info->rst); - goto err_dispose; + goto err_unprepare; } ret = reset_control_deassert(info->rst); if (ret) - goto err_dispose; + goto err_unprepare; port->type = type; port->uartclk = clk; @@ -184,8 +190,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->handle_irq = fsl8250_handle_irq; return 0; -err_dispose: - irq_dispose_mapping(port->irq); err_unprepare: clk_disable_unprepare(info->clk); err_pmruntime: diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3f779d25ec0c..f776b3eafb96 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -552,11 +552,30 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) */ static void serial8250_clear_fifos(struct uart_8250_port *p) { + unsigned char fcr; + unsigned char clr_mask = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT; + if (p->capabilities & UART_CAP_FIFO) { - serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(p, UART_FCR, 0); + /* + * Make sure to avoid changing FCR[7:3] and ENABLE_FIFO bits. + * In case ENABLE_FIFO is not set, there is nothing to flush + * so just return. Furthermore, on certain implementations of + * the 8250 core, the FCR[7:3] bits may only be changed under + * specific conditions and changing them if those conditions + * are not met can have nasty side effects. One such core is + * the 8250-omap present in TI AM335x. + */ + fcr = serial_in(p, UART_FCR); + + /* FIFO is not enabled, there's nothing to clear. */ + if (!(fcr & UART_FCR_ENABLE_FIFO)) + return; + + fcr |= clr_mask; + serial_out(p, UART_FCR, fcr); + + fcr &= ~clr_mask; + serial_out(p, UART_FCR, fcr); } } @@ -1448,7 +1467,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p) * Enable previously disabled RX interrupts. */ if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { - serial8250_clear_and_reinit_fifos(p); + serial8250_clear_fifos(p); p->ier |= UART_IER_RLSI | UART_IER_RDI; serial_port_out(&p->port, UART_IER, p->ier); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index f005eaf8bc57..15c2c5463835 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -375,7 +375,7 @@ config SERIAL_8250_RT288X config SERIAL_8250_OMAP tristate "Support for OMAP internal UART (8250 based driver)" - depends on SERIAL_8250 && ARCH_OMAP2PLUS + depends on SERIAL_8250 && (ARCH_OMAP2PLUS || ARCH_K3) help If you have a machine based on an Texas Instruments OMAP CPU you can enable its onboard serial ports by enabling this option. diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index df8bd0c7b97d..32886c304641 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -118,6 +118,7 @@ config SERIAL_ATMEL depends on ARCH_AT91 || COMPILE_TEST select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB + select MFD_AT91_USART help This enables the driver for the on-chip UARTs of the Atmel AT91 processors. diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 8e4428725848..267d4d1de3f8 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -193,8 +193,7 @@ static struct console atmel_console; #if defined(CONFIG_OF) static const struct of_device_id atmel_serial_dt_ids[] = { - { .compatible = "atmel,at91rm9200-usart" }, - { .compatible = "atmel,at91sam9260-usart" }, + { .compatible = "atmel,at91rm9200-usart-serial" }, { /* sentinel */ } }; #endif @@ -915,6 +914,7 @@ static void atmel_tx_dma(struct uart_port *port) static int atmel_prepare_tx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct device *mfd_dev = port->dev->parent; dma_cap_mask_t mask; struct dma_slave_config config; int ret, nent; @@ -922,7 +922,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - atmel_port->chan_tx = dma_request_slave_channel(port->dev, "tx"); + atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx"); if (atmel_port->chan_tx == NULL) goto chan_err; dev_info(port->dev, "using %s for tx DMA transfers\n", @@ -1093,6 +1093,7 @@ static void atmel_rx_from_dma(struct uart_port *port) static int atmel_prepare_rx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct device *mfd_dev = port->dev->parent; struct dma_async_tx_descriptor *desc; dma_cap_mask_t mask; struct dma_slave_config config; @@ -1104,7 +1105,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) dma_cap_zero(mask); dma_cap_set(DMA_CYCLIC, mask); - atmel_port->chan_rx = dma_request_slave_channel(port->dev, "rx"); + atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx"); if (atmel_port->chan_rx == NULL) goto chan_err; dev_info(port->dev, "using %s for rx DMA transfers\n", @@ -2222,8 +2223,8 @@ static const char *atmel_type(struct uart_port *port) */ static void atmel_release_port(struct uart_port *port) { - struct platform_device *pdev = to_platform_device(port->dev); - int size = pdev->resource[0].end - pdev->resource[0].start + 1; + struct platform_device *mpdev = to_platform_device(port->dev->parent); + int size = resource_size(mpdev->resource); release_mem_region(port->mapbase, size); @@ -2238,8 +2239,8 @@ static void atmel_release_port(struct uart_port *port) */ static int atmel_request_port(struct uart_port *port) { - struct platform_device *pdev = to_platform_device(port->dev); - int size = pdev->resource[0].end - pdev->resource[0].start + 1; + struct platform_device *mpdev = to_platform_device(port->dev->parent); + int size = resource_size(mpdev->resource); if (!request_mem_region(port->mapbase, size, "atmel_serial")) return -EBUSY; @@ -2341,27 +2342,28 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, { int ret; struct uart_port *port = &atmel_port->uart; + struct platform_device *mpdev = to_platform_device(pdev->dev.parent); atmel_init_property(atmel_port, pdev); atmel_set_ops(port); - uart_get_rs485_mode(&pdev->dev, &port->rs485); + uart_get_rs485_mode(&mpdev->dev, &port->rs485); port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->ops = &atmel_pops; port->fifosize = 1; port->dev = &pdev->dev; - port->mapbase = pdev->resource[0].start; - port->irq = pdev->resource[1].start; + port->mapbase = mpdev->resource[0].start; + port->irq = mpdev->resource[1].start; port->rs485_config = atmel_config_rs485; - port->membase = NULL; + port->membase = NULL; memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); /* for console, the clock could already be configured */ if (!atmel_port->clk) { - atmel_port->clk = clk_get(&pdev->dev, "usart"); + atmel_port->clk = clk_get(&mpdev->dev, "usart"); if (IS_ERR(atmel_port->clk)) { ret = PTR_ERR(atmel_port->clk); atmel_port->clk = NULL; @@ -2694,13 +2696,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port, static int atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *atmel_port; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = pdev->dev.parent->of_node; void *data; int ret = -ENODEV; bool rs485_enabled; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); + /* + * In device tree there is no node with "atmel,at91rm9200-usart-serial" + * as compatible string. This driver is probed by at91-usart mfd driver + * which is just a wrapper over the atmel_serial driver and + * spi-at91-usart driver. All attributes needed by this driver are + * found in of_node of parent. + */ + pdev->dev.of_node = np; + ret = of_alias_get_id(np, "serial"); if (ret < 0) /* port id not found in platform data nor device-tree aliases: @@ -2836,6 +2847,7 @@ static int atmel_serial_remove(struct platform_device *pdev) clk_put(atmel_port->clk); atmel_port->clk = NULL; + pdev->dev.of_node = NULL; return ret; } @@ -2846,7 +2858,7 @@ static struct platform_driver atmel_serial_driver = { .suspend = atmel_serial_suspend, .resume = atmel_serial_resume, .driver = { - .name = "atmel_usart", + .name = "atmel_usart_serial", .of_match_table = of_match_ptr(atmel_serial_dt_ids), }, }; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index e5389591bb4f..79ad30d34949 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1155,8 +1155,8 @@ static int cpm_uart_init_port(struct device_node *np, if (!pinfo->clk) { data = of_get_property(np, "fsl,cpm-brg", &len); if (!data || len != 4) { - printk(KERN_ERR "CPM UART %s has no/invalid " - "fsl,cpm-brg property.\n", np->name); + printk(KERN_ERR "CPM UART %pOFn has no/invalid " + "fsl,cpm-brg property.\n", np); return -EINVAL; } pinfo->brg = *data; @@ -1164,8 +1164,8 @@ static int cpm_uart_init_port(struct device_node *np, data = of_get_property(np, "fsl,cpm-command", &len); if (!data || len != 4) { - printk(KERN_ERR "CPM UART %s has no/invalid " - "fsl,cpm-command property.\n", np->name); + printk(KERN_ERR "CPM UART %pOFn has no/invalid " + "fsl,cpm-command property.\n", np); return -EINVAL; } pinfo->command = *data; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0f67197a3783..d4e051b578f6 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -24,6 +24,7 @@ #include <linux/serial.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/pinctrl/consumer.h> #include <linux/rational.h> #include <linux/slab.h> #include <linux/of.h> @@ -706,27 +707,25 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id) { struct imx_port *sport = dev_id; u32 usr1; - unsigned long flags; - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); imx_uart_writel(sport, USR1_RTSD, USR1); usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS; uart_handle_cts_change(&sport->port, !!usr1); wake_up_interruptible(&sport->port.state->port.delta_msr_wait); - spin_unlock_irqrestore(&sport->port.lock, flags); + spin_unlock(&sport->port.lock); return IRQ_HANDLED; } static irqreturn_t imx_uart_txint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned long flags; - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); imx_uart_transmit_buffer(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + spin_unlock(&sport->port.lock); return IRQ_HANDLED; } @@ -735,9 +734,8 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id) struct imx_port *sport = dev_id; unsigned int rx, flg, ignored = 0; struct tty_port *port = &sport->port.state->port; - unsigned long flags; - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); while (imx_uart_readl(sport, USR2) & USR2_RDR) { u32 usr2; @@ -797,7 +795,7 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id) } out: - spin_unlock_irqrestore(&sport->port.lock, flags); + spin_unlock(&sport->port.lock); tty_flip_buffer_push(port); return IRQ_HANDLED; } @@ -903,13 +901,11 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) } if (usr1 & USR1_DTRD) { - unsigned long flags; - imx_uart_writel(sport, USR1_DTRD, USR1); - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); imx_uart_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + spin_unlock(&sport->port.lock); ret = IRQ_HANDLED; } @@ -2384,8 +2380,13 @@ static int imx_uart_remove(struct platform_device *pdev) static void imx_uart_restore_context(struct imx_port *sport) { - if (!sport->context_saved) + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + if (!sport->context_saved) { + spin_unlock_irqrestore(&sport->port.lock, flags); return; + } imx_uart_writel(sport, sport->saved_reg[4], UFCR); imx_uart_writel(sport, sport->saved_reg[5], UESC); @@ -2398,11 +2399,15 @@ static void imx_uart_restore_context(struct imx_port *sport) imx_uart_writel(sport, sport->saved_reg[2], UCR3); imx_uart_writel(sport, sport->saved_reg[3], UCR4); sport->context_saved = false; + spin_unlock_irqrestore(&sport->port.lock, flags); } static void imx_uart_save_context(struct imx_port *sport) { + unsigned long flags; + /* Save necessary regs */ + spin_lock_irqsave(&sport->port.lock, flags); sport->saved_reg[0] = imx_uart_readl(sport, UCR1); sport->saved_reg[1] = imx_uart_readl(sport, UCR2); sport->saved_reg[2] = imx_uart_readl(sport, UCR3); @@ -2414,6 +2419,7 @@ static void imx_uart_save_context(struct imx_port *sport) sport->saved_reg[8] = imx_uart_readl(sport, UBMR); sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS); sport->context_saved = true; + spin_unlock_irqrestore(&sport->port.lock, flags); } static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) @@ -2447,6 +2453,8 @@ static int imx_uart_suspend_noirq(struct device *dev) clk_disable(sport->clk_ipg); + pinctrl_pm_select_sleep_state(dev); + return 0; } @@ -2455,6 +2463,8 @@ static int imx_uart_resume_noirq(struct device *dev) struct imx_port *sport = dev_get_drvdata(dev); int ret; + pinctrl_pm_select_default_state(dev); + ret = clk_enable(sport->clk_ipg); if (ret) return ret; diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index b4ba2b1dab76..baeeeaec3f03 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -8,6 +8,9 @@ * * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/ctype.h> #include <linux/kgdb.h> @@ -128,19 +131,6 @@ static void kgdboc_unregister_kbd(void) #define kgdboc_restore_input() #endif /* ! CONFIG_KDB_KEYBOARD */ -static int kgdboc_option_setup(char *opt) -{ - if (strlen(opt) >= MAX_CONFIG_LEN) { - printk(KERN_ERR "kgdboc: config string too long\n"); - return -ENOSPC; - } - strcpy(config, opt); - - return 0; -} - -__setup("kgdboc=", kgdboc_option_setup); - static void cleanup_kgdboc(void) { if (kgdb_unregister_nmi_console()) @@ -154,15 +144,13 @@ static int configure_kgdboc(void) { struct tty_driver *p; int tty_line = 0; - int err; + int err = -ENODEV; char *cptr = config; struct console *cons; - err = kgdboc_option_setup(config); - if (err || !strlen(config) || isspace(config[0])) + if (!strlen(config) || isspace(config[0])) goto noconfig; - err = -ENODEV; kgdboc_io_ops.is_console = 0; kgdb_tty_driver = NULL; @@ -248,7 +236,7 @@ static int param_set_kgdboc_var(const char *kmessage, int len = strlen(kmessage); if (len >= MAX_CONFIG_LEN) { - printk(KERN_ERR "kgdboc: config string too long\n"); + pr_err("config string too long\n"); return -ENOSPC; } @@ -259,8 +247,7 @@ static int param_set_kgdboc_var(const char *kmessage, } if (kgdb_connected) { - printk(KERN_ERR - "kgdboc: Cannot reconfigure while KGDB is connected.\n"); + pr_err("Cannot reconfigure while KGDB is connected.\n"); return -EBUSY; } @@ -311,6 +298,25 @@ static struct kgdb_io kgdboc_io_ops = { }; #ifdef CONFIG_KGDB_SERIAL_CONSOLE +static int kgdboc_option_setup(char *opt) +{ + if (!opt) { + pr_err("config string not provided\n"); + return -EINVAL; + } + + if (strlen(opt) >= MAX_CONFIG_LEN) { + pr_err("config string too long\n"); + return -ENOSPC; + } + strcpy(config, opt); + + return 0; +} + +__setup("kgdboc=", kgdboc_option_setup); + + /* This is only available if kgdboc is a built in for early debugging */ static int __init kgdboc_early_init(char *opt) { diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 76aa289652f7..27235a526cce 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1634,8 +1634,9 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s) /* * If something went wrong, rollback. + * Be careful: i may be unsigned. */ - while (err && (--i >= 0)) + while (err && (i-- > 0)) if (irq[i] >= 0) free_irq(irq[i], s); diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 3d21790d961e..a9d40988e1c8 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -219,7 +219,7 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable) static bool pmz_receive_chars(struct uart_pmac_port *uap) { struct tty_port *port; - unsigned char ch, r1, drop, error, flag; + unsigned char ch, r1, drop, flag; int loops = 0; /* Sanity check, make sure the old bug is no longer happening */ @@ -231,7 +231,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) port = &uap->port.state->port; while (1) { - error = 0; drop = 0; r1 = read_zsreg(uap, R1); @@ -273,7 +272,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) uap->port.icount.rx++; if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) { - error = 1; if (r1 & BRK_ABRT) { pmz_debug("pmz: got break !\n"); r1 &= ~(PAR_ERR | CRC_ERR); @@ -1566,9 +1564,9 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) * to work around bugs in ancient Apple device-trees */ if (macio_request_resources(uap->dev, "pmac_zilog")) - printk(KERN_WARNING "%s: Failed to request resource" + printk(KERN_WARNING "%pOFn: Failed to request resource" ", port still active\n", - uap->node->name); + uap->node); else uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 29ec34387246..e80d50723a75 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -851,6 +851,23 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport, uport); unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; + u32 proto; + + if (uart_console(uport)) + port->tx_bytes_pw = 1; + else + port->tx_bytes_pw = 4; + port->rx_bytes_pw = RX_BYTES_PW; + + proto = geni_se_read_proto(&port->se); + if (proto != GENI_SE_UART) { + dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto); + return -ENXIO; + } + + qcom_geni_serial_stop_rx(uport); + + get_tx_fifo_size(port); set_rfr_wm(port); writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT); @@ -874,30 +891,19 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) return -ENOMEM; } port->setup = true; + return 0; } static int qcom_geni_serial_startup(struct uart_port *uport) { int ret; - u32 proto; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); scnprintf(port->name, sizeof(port->name), "qcom_serial_%s%d", (uart_console(uport) ? "console" : "uart"), uport->line); - if (!uart_console(uport)) { - port->tx_bytes_pw = 4; - port->rx_bytes_pw = RX_BYTES_PW; - } - proto = geni_se_read_proto(&port->se); - if (proto != GENI_SE_UART) { - dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto); - return -ENXIO; - } - - get_tx_fifo_size(port); if (!port->setup) { ret = qcom_geni_serial_port_setup(uport); if (ret) @@ -1056,6 +1062,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; + int ret; if (co->index >= GENI_UART_CONS_PORTS || co->index < 0) return -ENXIO; @@ -1071,21 +1078,10 @@ static int __init qcom_geni_console_setup(struct console *co, char *options) if (unlikely(!uport->membase)) return -ENXIO; - if (geni_se_resources_on(&port->se)) { - dev_err(port->se.dev, "Error turning on resources\n"); - return -ENXIO; - } - - if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) { - geni_se_resources_off(&port->se); - return -ENXIO; - } - if (!port->setup) { - port->tx_bytes_pw = 1; - port->rx_bytes_pw = RX_BYTES_PW; - qcom_geni_serial_stop_rx(uport); - qcom_geni_serial_port_setup(uport); + ret = qcom_geni_serial_port_setup(uport); + if (ret) + return ret; } if (options) @@ -1203,11 +1199,12 @@ static void qcom_geni_serial_pm(struct uart_port *uport, { struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + /* If we've never been called, treat it as off */ + if (old_state == UART_PM_STATE_UNDEFINED) + old_state = UART_PM_STATE_OFF; + if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) geni_se_resources_on(&port->se); - else if (!uart_console(uport) && (new_state == UART_PM_STATE_ON && - old_state == UART_PM_STATE_UNDEFINED)) - geni_se_resources_on(&port->se); else if (new_state == UART_PM_STATE_OFF && old_state == UART_PM_STATE_ON) geni_se_resources_off(&port->se); @@ -1263,14 +1260,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart")) console = true; - if (pdev->dev.of_node) { - if (console) { - drv = &qcom_geni_console_driver; - line = of_alias_get_id(pdev->dev.of_node, "serial"); - } else { - drv = &qcom_geni_uart_driver; - line = of_alias_get_id(pdev->dev.of_node, "hsuart"); - } + if (console) { + drv = &qcom_geni_console_driver; + line = of_alias_get_id(pdev->dev.of_node, "serial"); + } else { + drv = &qcom_geni_uart_driver; + line = of_alias_get_id(pdev->dev.of_node, "hsuart"); } port = get_port_from_line(line, console); diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 2f8fa184aafa..da1bd4bba8a9 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1941,7 +1941,11 @@ static int s3c24xx_serial_resume(struct device *dev) if (port) { clk_prepare_enable(ourport->clk); + if (!IS_ERR(ourport->baudclk)) + clk_prepare_enable(ourport->baudclk); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); clk_disable_unprepare(ourport->clk); uart_resume_port(&s3c24xx_uart_drv, port); @@ -1964,7 +1968,11 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) if (rx_enabled(port)) uintm &= ~S3C64XX_UINTM_RXD_MSK; clk_prepare_enable(ourport->clk); + if (!IS_ERR(ourport->baudclk)) + clk_prepare_enable(ourport->baudclk); wr_regl(port, S3C64XX_UINTM, uintm); + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); clk_disable_unprepare(ourport->clk); } } diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 243c96025053..268098681856 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -328,6 +328,7 @@ struct sc16is7xx_port { struct kthread_worker kworker; struct task_struct *kworker_task; struct kthread_work irq_work; + struct mutex efr_lock; struct sc16is7xx_one p[0]; }; @@ -499,6 +500,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) div /= 4; } + /* In an amazing feat of design, the Enhanced Features Register shares + * the address of the Interrupt Identification Register, and is + * switched in by writing a magic value (0xbf) to the Line Control + * Register. Any interrupt firing during this time will see the EFR + * where it expects the IIR to be, leading to "Unexpected interrupt" + * messages. + * + * Prevent this possibility by claiming a mutex while accessing the + * EFR, and claiming the same mutex from within the interrupt handler. + * This is similar to disabling the interrupt, but that doesn't work + * because the bulk of the interrupt processing is run as a workqueue + * job in thread context. + */ + mutex_lock(&s->efr_lock); + lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); /* Open the LCR divisors for configuration */ @@ -514,6 +530,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) /* Put LCR back to the normal mode */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + mutex_unlock(&s->efr_lock); + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_CLKSEL_BIT, prescaler); @@ -657,7 +675,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port) uart_write_wakeup(port); } -static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) +static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) { struct uart_port *port = &s->p[portno].port; @@ -666,7 +684,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); if (iir & SC16IS7XX_IIR_NO_INT_BIT) - break; + return false; iir &= SC16IS7XX_IIR_ID_MASK; @@ -688,16 +706,27 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) port->line, iir); break; } - } while (1); + } while (0); + return true; } static void sc16is7xx_ist(struct kthread_work *ws) { struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); - int i; - for (i = 0; i < s->devtype->nr_uart; ++i) - sc16is7xx_port_irq(s, i); + mutex_lock(&s->efr_lock); + + while (1) { + bool keep_polling = false; + int i; + + for (i = 0; i < s->devtype->nr_uart; ++i) + keep_polling |= sc16is7xx_port_irq(s, i); + if (!keep_polling) + break; + } + + mutex_unlock(&s->efr_lock); } static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) @@ -892,6 +921,9 @@ static void sc16is7xx_set_termios(struct uart_port *port, if (!(termios->c_cflag & CREAD)) port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; + /* As above, claim the mutex while accessing the EFR. */ + mutex_lock(&s->efr_lock); + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B); @@ -913,6 +945,8 @@ static void sc16is7xx_set_termios(struct uart_port *port, /* Update LCR register */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + mutex_unlock(&s->efr_lock); + /* Get baud rate generator configuration */ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 16 / 4 / 0xffff, @@ -1178,6 +1212,7 @@ static int sc16is7xx_probe(struct device *dev, s->regmap = regmap; s->devtype = devtype; dev_set_drvdata(dev, s); + mutex_init(&s->efr_lock); kthread_init_worker(&s->kworker); kthread_init_work(&s->irq_work, sc16is7xx_ist); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index ac4424bf6b13..426241da2e44 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -292,6 +292,33 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { }, /* + * The "SCIFA" that is in RZ/T and RZ/A2. + * It looks like a normal SCIF with FIFO data, but with a + * compressed address space. Also, the break out of interrupts + * are different: ERI/BRI, RXI, TXI, TEI, DRI. + */ + [SCIx_RZ_SCIFA_REGTYPE] = { + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x02, 8 }, + [SCSCR] = { 0x04, 16 }, + [SCxTDR] = { 0x06, 8 }, + [SCxSR] = { 0x08, 16 }, + [SCxRDR] = { 0x0A, 8 }, + [SCFCR] = { 0x0C, 16 }, + [SCFDR] = { 0x0E, 16 }, + [SCSPTR] = { 0x10, 16 }, + [SCLSR] = { 0x12, 16 }, + }, + .fifosize = 16, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, + }, + + /* * Common SH-3 SCIF definitions. */ [SCIx_SH3_SCIF_REGTYPE] = { @@ -319,15 +346,15 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { [SCIx_SH4_SCIF_REGTYPE] = { .regs = { [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x02, 8 }, - [SCSCR] = { 0x04, 16 }, - [SCxTDR] = { 0x06, 8 }, - [SCxSR] = { 0x08, 16 }, - [SCxRDR] = { 0x0a, 8 }, - [SCFCR] = { 0x0c, 16 }, - [SCFDR] = { 0x0e, 16 }, - [SCSPTR] = { 0x10, 16 }, - [SCLSR] = { 0x12, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCSPTR] = { 0x20, 16 }, + [SCLSR] = { 0x24, 16 }, }, .fifosize = 16, .overrun_reg = SCLSR, @@ -2810,7 +2837,7 @@ static int sci_init_single(struct platform_device *dev, { struct uart_port *port = &sci_port->port; const struct resource *res; - unsigned int i, regtype; + unsigned int i; int ret; sci_port->cfg = p; @@ -2847,7 +2874,6 @@ static int sci_init_single(struct platform_device *dev, if (unlikely(sci_port->params == NULL)) return -EINVAL; - regtype = sci_port->params - sci_port_params; switch (p->type) { case PORT_SCIFB: sci_port->rx_trigger = 48; @@ -2902,10 +2928,6 @@ static int sci_init_single(struct platform_device *dev, port->regshift = 1; } - if (regtype == SCIx_SH4_SCIF_REGTYPE) - if (sci_port->reg_size >= 0x20) - port->regshift = 1; - /* * The UART port needs an IRQ value, so we peg this to the RX IRQ * for the multi-IRQ ports, which is where we are primarily @@ -3110,6 +3132,10 @@ static const struct of_device_id of_sci_match[] = { .compatible = "renesas,scif-r7s72100", .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE), }, + { + .compatible = "renesas,scif-r7s9210", + .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE), + }, /* Family-specific types */ { .compatible = "renesas,rcar-gen1-scif", @@ -3388,6 +3414,12 @@ static int __init scif_early_console_setup(struct earlycon_device *device, { return early_console_setup(device, PORT_SCIF); } +static int __init rzscifa_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE; + return early_console_setup(device, PORT_SCIF); +} static int __init scifa_early_console_setup(struct earlycon_device *device, const char *opt) { @@ -3406,6 +3438,7 @@ static int __init hscif_early_console_setup(struct earlycon_device *device, OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup); +OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup); OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup); OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup); OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup); diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 828f1143859c..4287ca305b6b 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -45,6 +45,8 @@ /* data number in TX and RX fifo */ #define SPRD_STS1 0x000C +#define SPRD_RX_FIFO_CNT_MASK GENMASK(7, 0) +#define SPRD_TX_FIFO_CNT_MASK GENMASK(15, 8) /* interrupt enable register and its BITs */ #define SPRD_IEN 0x0010 @@ -66,67 +68,62 @@ #define SPRD_LCR_DATA_LEN6 0x4 #define SPRD_LCR_DATA_LEN7 0x8 #define SPRD_LCR_DATA_LEN8 0xc -#define SPRD_LCR_PARITY (BIT(0) | BIT(1)) +#define SPRD_LCR_PARITY (BIT(0) | BIT(1)) #define SPRD_LCR_PARITY_EN 0x2 #define SPRD_LCR_EVEN_PAR 0x0 #define SPRD_LCR_ODD_PAR 0x1 /* control register 1 */ -#define SPRD_CTL1 0x001C +#define SPRD_CTL1 0x001C #define RX_HW_FLOW_CTL_THLD BIT(6) #define RX_HW_FLOW_CTL_EN BIT(7) #define TX_HW_FLOW_CTL_EN BIT(8) #define RX_TOUT_THLD_DEF 0x3E00 -#define RX_HFC_THLD_DEF 0x40 +#define RX_HFC_THLD_DEF 0x40 /* fifo threshold register */ #define SPRD_CTL2 0x0020 -#define THLD_TX_EMPTY 0x40 -#define THLD_RX_FULL 0x40 +#define THLD_TX_EMPTY 0x40 +#define THLD_TX_EMPTY_SHIFT 8 +#define THLD_RX_FULL 0x40 /* config baud rate register */ #define SPRD_CLKD0 0x0024 +#define SPRD_CLKD0_MASK GENMASK(15, 0) #define SPRD_CLKD1 0x0028 +#define SPRD_CLKD1_MASK GENMASK(20, 16) +#define SPRD_CLKD1_SHIFT 16 /* interrupt mask status register */ -#define SPRD_IMSR 0x002C -#define SPRD_IMSR_RX_FIFO_FULL BIT(0) +#define SPRD_IMSR 0x002C +#define SPRD_IMSR_RX_FIFO_FULL BIT(0) #define SPRD_IMSR_TX_FIFO_EMPTY BIT(1) -#define SPRD_IMSR_BREAK_DETECT BIT(7) -#define SPRD_IMSR_TIMEOUT BIT(13) - -struct reg_backup { - u32 ien; - u32 ctrl0; - u32 ctrl1; - u32 ctrl2; - u32 clkd0; - u32 clkd1; - u32 dspwait; -}; +#define SPRD_IMSR_BREAK_DETECT BIT(7) +#define SPRD_IMSR_TIMEOUT BIT(13) struct sprd_uart_port { struct uart_port port; - struct reg_backup reg_bak; char name[16]; }; static struct sprd_uart_port *sprd_port[UART_NR_MAX]; static int sprd_ports_num; -static inline unsigned int serial_in(struct uart_port *port, int offset) +static inline unsigned int serial_in(struct uart_port *port, + unsigned int offset) { return readl_relaxed(port->membase + offset); } -static inline void serial_out(struct uart_port *port, int offset, int value) +static inline void serial_out(struct uart_port *port, unsigned int offset, + int value) { writel_relaxed(value, port->membase + offset); } static unsigned int sprd_tx_empty(struct uart_port *port) { - if (serial_in(port, SPRD_STS1) & 0xff00) + if (serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK) return 0; else return TIOCSER_TEMT; @@ -224,14 +221,15 @@ static inline void sprd_rx(struct uart_port *port) struct tty_port *tty = &port->state->port; unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT; - while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) { + while ((serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK) && + max_count--) { lsr = serial_in(port, SPRD_LSR); ch = serial_in(port, SPRD_RXD); flag = TTY_NORMAL; port->icount.rx++; if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE | - SPRD_LSR_FE | SPRD_LSR_OE)) + SPRD_LSR_FE | SPRD_LSR_OE)) if (handle_lsr_errors(port, &lsr, &flag)) continue; if (uart_handle_sysrq_char(port, ch)) @@ -294,8 +292,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) if (ims & SPRD_IMSR_TIMEOUT) serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT); - if (ims & (SPRD_IMSR_RX_FIFO_FULL | - SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT)) + if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT | + SPRD_IMSR_TIMEOUT)) sprd_rx(port); if (ims & SPRD_IMSR_TX_FIFO_EMPTY) @@ -314,16 +312,17 @@ static int sprd_startup(struct uart_port *port) struct sprd_uart_port *sp; unsigned long flags; - serial_out(port, SPRD_CTL2, ((THLD_TX_EMPTY << 8) | THLD_RX_FULL)); + serial_out(port, SPRD_CTL2, + THLD_TX_EMPTY << THLD_TX_EMPTY_SHIFT | THLD_RX_FULL); /* clear rx fifo */ timeout = SPRD_TIMEOUT; - while (timeout-- && serial_in(port, SPRD_STS1) & 0x00ff) + while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK) serial_in(port, SPRD_RXD); /* clear tx fifo */ timeout = SPRD_TIMEOUT; - while (timeout-- && serial_in(port, SPRD_STS1) & 0xff00) + while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK) cpu_relax(); /* clear interrupt */ @@ -334,7 +333,7 @@ static int sprd_startup(struct uart_port *port) sp = container_of(port, struct sprd_uart_port, port); snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line); ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq, - IRQF_SHARED, sp->name, port); + IRQF_SHARED, sp->name, port); if (ret) { dev_err(port->dev, "fail to request serial irq %d, ret=%d\n", port->irq, ret); @@ -362,8 +361,8 @@ static void sprd_shutdown(struct uart_port *port) } static void sprd_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) + struct ktermios *termios, + struct ktermios *old) { unsigned int baud, quot; unsigned int lcr = 0, fc; @@ -444,10 +443,11 @@ static void sprd_set_termios(struct uart_port *port, } /* clock divider bit0~bit15 */ - serial_out(port, SPRD_CLKD0, quot & 0xffff); + serial_out(port, SPRD_CLKD0, quot & SPRD_CLKD0_MASK); /* clock divider bit16~bit20 */ - serial_out(port, SPRD_CLKD1, (quot & 0x1f0000) >> 16); + serial_out(port, SPRD_CLKD1, + (quot & SPRD_CLKD1_MASK) >> SPRD_CLKD1_SHIFT); serial_out(port, SPRD_LCR, lcr); fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF; serial_out(port, SPRD_CTL1, fc); @@ -480,8 +480,7 @@ static void sprd_config_port(struct uart_port *port, int flags) port->type = PORT_SPRD; } -static int sprd_verify_port(struct uart_port *port, - struct serial_struct *ser) +static int sprd_verify_port(struct uart_port *port, struct serial_struct *ser) { if (ser->type != PORT_SPRD) return -EINVAL; @@ -521,7 +520,7 @@ static void wait_for_xmitr(struct uart_port *port) if (--tmout == 0) break; udelay(1); - } while (status & 0xff00); + } while (status & SPRD_TX_FIFO_CNT_MASK); } static void sprd_console_putchar(struct uart_port *port, int ch) @@ -531,7 +530,7 @@ static void sprd_console_putchar(struct uart_port *port, int ch) } static void sprd_console_write(struct console *co, const char *s, - unsigned int count) + unsigned int count) { struct uart_port *port = &sprd_port[co->index]->port; int locked = 1; @@ -594,23 +593,21 @@ static void sprd_putc(struct uart_port *port, int c) unsigned int timeout = SPRD_TIMEOUT; while (timeout-- && - !(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER)) + !(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER)) cpu_relax(); writeb(c, port->membase + SPRD_TXD); } -static void sprd_early_write(struct console *con, const char *s, - unsigned n) +static void sprd_early_write(struct console *con, const char *s, unsigned int n) { struct earlycon_device *dev = con->data; uart_console_write(&dev->port, s, n, sprd_putc); } -static int __init sprd_early_console_setup( - struct earlycon_device *device, - const char *opt) +static int __init sprd_early_console_setup(struct earlycon_device *device, + const char *opt) { if (!device->port.membase) return -ENODEV; @@ -692,8 +689,8 @@ static int sprd_probe(struct platform_device *pdev) index = sprd_probe_dt_alias(index, &pdev->dev); - sprd_port[index] = devm_kzalloc(&pdev->dev, - sizeof(*sprd_port[index]), GFP_KERNEL); + sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]), + GFP_KERNEL); if (!sprd_port[index]) return -ENOMEM; @@ -712,15 +709,12 @@ static int sprd_probe(struct platform_device *pdev) up->uartclk = clk_get_rate(clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "not provide mem resource\n"); - return -ENODEV; - } - up->mapbase = res->start; up->membase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(up->membase)) return PTR_ERR(up->membase); + up->mapbase = res->start; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "not provide irq resource: %d\n", irq); diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 98d3eadd2fd0..f0344adc86db 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -55,6 +55,11 @@ #define ULITE_CONTROL_RST_RX 0x02 #define ULITE_CONTROL_IE 0x10 +/* Static pointer to console port */ +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE +static struct uart_port *console_port; +#endif + struct uartlite_data { const struct uartlite_reg_ops *reg_ops; struct clk *clk; @@ -472,7 +477,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch) static void ulite_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &ulite_ports[co->index]; + struct uart_port *port = console_port; unsigned long flags; unsigned int ier; int locked = 1; @@ -506,10 +511,8 @@ static int ulite_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - if (co->index < 0 || co->index >= ULITE_NR_UARTS) - return -EINVAL; - port = &ulite_ports[co->index]; + port = console_port; /* Has the device been initialized yet? */ if (!port->mapbase) { @@ -541,14 +544,6 @@ static struct console ulite_console = { .data = &ulite_uart_driver, }; -static int __init ulite_console_init(void) -{ - register_console(&ulite_console); - return 0; -} - -console_initcall(ulite_console_init); - static void early_uartlite_putc(struct uart_port *port, int c) { /* @@ -660,6 +655,17 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, dev_set_drvdata(dev, port); +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE + /* + * If console hasn't been found yet try to assign this port + * because it is required to be assigned for console setup function. + * If register_console() don't assign value, then console_port pointer + * is cleanup. + */ + if (ulite_uart_driver.cons->index == -1) + console_port = port; +#endif + /* Register the port */ rc = uart_add_one_port(&ulite_uart_driver, port); if (rc) { @@ -669,6 +675,12 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, return rc; } +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE + /* This is not port which is used for console that's why clean it up */ + if (ulite_uart_driver.cons->index == -1) + console_port = NULL; +#endif + return 0; } @@ -776,13 +788,26 @@ static int ulite_probe(struct platform_device *pdev) pdata->clk = NULL; } - ret = clk_prepare(pdata->clk); + ret = clk_prepare_enable(pdata->clk); if (ret) { dev_err(&pdev->dev, "Failed to prepare clock\n"); return ret; } - return ulite_assign(&pdev->dev, id, res->start, irq, pdata); + if (!ulite_uart_driver.state) { + dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n"); + ret = uart_register_driver(&ulite_uart_driver); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register driver\n"); + return ret; + } + } + + ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata); + + clk_disable(pdata->clk); + + return ret; } static int ulite_remove(struct platform_device *pdev) @@ -813,25 +838,9 @@ static struct platform_driver ulite_platform_driver = { static int __init ulite_init(void) { - int ret; - - pr_debug("uartlite: calling uart_register_driver()\n"); - ret = uart_register_driver(&ulite_uart_driver); - if (ret) - goto err_uart; pr_debug("uartlite: calling platform_driver_register()\n"); - ret = platform_driver_register(&ulite_platform_driver); - if (ret) - goto err_plat; - - return 0; - -err_plat: - uart_unregister_driver(&ulite_uart_driver); -err_uart: - pr_err("registering uartlite driver failed: err=%i\n", ret); - return ret; + return platform_driver_register(&ulite_platform_driver); } static void __exit ulite_exit(void) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index a48f19b1b88f..f77200a0f461 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -30,8 +30,6 @@ #define CDNS_UART_TTY_NAME "ttyPS" #define CDNS_UART_NAME "xuartps" #define CDNS_UART_MAJOR 0 /* use dynamic node allocation */ -#define CDNS_UART_MINOR 0 /* works best with devtmpfs */ -#define CDNS_UART_NR_PORTS 2 #define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ #define CDNS_UART_REGISTER_SPACE 0x1000 @@ -180,7 +178,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); * @port: Pointer to the UART port * @uartclk: Reference clock * @pclk: APB clock + * @cdns_uart_driver: Pointer to UART driver * @baud: Current baud rate + * @id: Port ID * @clk_rate_change_nb: Notifier block for clock changes * @quirks: Flags for RXBS support. */ @@ -188,7 +188,9 @@ struct cdns_uart { struct uart_port *port; struct clk *uartclk; struct clk *pclk; + struct uart_driver *cdns_uart_driver; unsigned int baud; + int id; struct notifier_block clk_rate_change_nb; u32 quirks; }; @@ -1003,13 +1005,12 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) val = readl(port->membase + CDNS_UART_MODEMCR); mode_reg = readl(port->membase + CDNS_UART_MR); - val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR); + val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR | + CDNS_UART_MODEMCR_FCM); mode_reg &= ~CDNS_UART_MR_CHMODE_MASK; - if (mctrl & TIOCM_RTS) - val |= CDNS_UART_MODEMCR_RTS; - if (mctrl & TIOCM_DTR) - val |= CDNS_UART_MODEMCR_DTR; + if (mctrl & TIOCM_RTS || mctrl & TIOCM_DTR) + val |= CDNS_UART_MODEMCR_FCM; if (mctrl & TIOCM_LOOP) mode_reg |= CDNS_UART_MR_CHMODE_L_LOOP; else @@ -1217,7 +1218,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, * * Return: 0 on success, negative errno otherwise. */ -static int __init cdns_uart_console_setup(struct console *co, char *options) +static int cdns_uart_console_setup(struct console *co, char *options) { struct uart_port *port = console_port; @@ -1237,32 +1238,8 @@ static int __init cdns_uart_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } - -static struct uart_driver cdns_uart_uart_driver; - -static struct console cdns_uart_console = { - .name = CDNS_UART_TTY_NAME, - .write = cdns_uart_console_write, - .device = uart_console_device, - .setup = cdns_uart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */ - .data = &cdns_uart_uart_driver, -}; #endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */ -static struct uart_driver cdns_uart_uart_driver = { - .owner = THIS_MODULE, - .driver_name = CDNS_UART_NAME, - .dev_name = CDNS_UART_TTY_NAME, - .major = CDNS_UART_MAJOR, - .minor = CDNS_UART_MINOR, - .nr = CDNS_UART_NR_PORTS, -#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE - .cons = &cdns_uart_console, -#endif -}; - #ifdef CONFIG_PM_SLEEP /** * cdns_uart_suspend - suspend event @@ -1273,24 +1250,12 @@ static struct uart_driver cdns_uart_uart_driver = { static int cdns_uart_suspend(struct device *device) { struct uart_port *port = dev_get_drvdata(device); - struct tty_struct *tty; - struct device *tty_dev; - int may_wake = 0; - - /* Get the tty which could be NULL so don't assume it's valid */ - tty = tty_port_tty_get(&port->state->port); - if (tty) { - tty_dev = tty->dev; - may_wake = device_may_wakeup(tty_dev); - tty_kref_put(tty); - } + struct cdns_uart *cdns_uart = port->private_data; + int may_wake; - /* - * Call the API provided in serial_core.c file which handles - * the suspend. - */ - uart_suspend_port(&cdns_uart_uart_driver, port); - if (!(console_suspend_enabled && !may_wake)) { + may_wake = device_may_wakeup(device); + + if (console_suspend_enabled && may_wake) { unsigned long flags = 0; spin_lock_irqsave(&port->lock, flags); @@ -1305,7 +1270,11 @@ static int cdns_uart_suspend(struct device *device) spin_unlock_irqrestore(&port->lock, flags); } - return 0; + /* + * Call the API provided in serial_core.c file which handles + * the suspend. + */ + return uart_suspend_port(cdns_uart->cdns_uart_driver, port); } /** @@ -1317,23 +1286,14 @@ static int cdns_uart_suspend(struct device *device) static int cdns_uart_resume(struct device *device) { struct uart_port *port = dev_get_drvdata(device); + struct cdns_uart *cdns_uart = port->private_data; unsigned long flags = 0; u32 ctrl_reg; - struct tty_struct *tty; - struct device *tty_dev; - int may_wake = 0; - - /* Get the tty which could be NULL so don't assume it's valid */ - tty = tty_port_tty_get(&port->state->port); - if (tty) { - tty_dev = tty->dev; - may_wake = device_may_wakeup(tty_dev); - tty_kref_put(tty); - } + int may_wake; - if (console_suspend_enabled && !may_wake) { - struct cdns_uart *cdns_uart = port->private_data; + may_wake = device_may_wakeup(device); + if (console_suspend_enabled && !may_wake) { clk_enable(cdns_uart->pclk); clk_enable(cdns_uart->uartclk); @@ -1367,7 +1327,7 @@ static int cdns_uart_resume(struct device *device) spin_unlock_irqrestore(&port->lock, flags); } - return uart_resume_port(&cdns_uart_uart_driver, port); + return uart_resume_port(cdns_uart->cdns_uart_driver, port); } #endif /* ! CONFIG_PM_SLEEP */ static int __maybe_unused cdns_runtime_suspend(struct device *dev) @@ -1409,6 +1369,88 @@ static const struct of_device_id cdns_uart_of_match[] = { }; MODULE_DEVICE_TABLE(of, cdns_uart_of_match); +/* + * Maximum number of instances without alias IDs but if there is alias + * which target "< MAX_UART_INSTANCES" range this ID can't be used. + */ +#define MAX_UART_INSTANCES 32 + +/* Stores static aliases list */ +static DECLARE_BITMAP(alias_bitmap, MAX_UART_INSTANCES); +static int alias_bitmap_initialized; + +/* Stores actual bitmap of allocated IDs with alias IDs together */ +static DECLARE_BITMAP(bitmap, MAX_UART_INSTANCES); +/* Protect bitmap operations to have unique IDs */ +static DEFINE_MUTEX(bitmap_lock); + +static int cdns_get_id(struct platform_device *pdev) +{ + int id, ret; + + mutex_lock(&bitmap_lock); + + /* Alias list is stable that's why get alias bitmap only once */ + if (!alias_bitmap_initialized) { + ret = of_alias_get_alias_list(cdns_uart_of_match, "serial", + alias_bitmap, MAX_UART_INSTANCES); + if (ret) + return ret; + + alias_bitmap_initialized++; + } + + /* Make sure that alias ID is not taken by instance without alias */ + bitmap_or(bitmap, bitmap, alias_bitmap, MAX_UART_INSTANCES); + + dev_dbg(&pdev->dev, "Alias bitmap: %*pb\n", + MAX_UART_INSTANCES, bitmap); + + /* Look for a serialN alias */ + id = of_alias_get_id(pdev->dev.of_node, "serial"); + if (id < 0) { + dev_warn(&pdev->dev, + "No serial alias passed. Using the first free id\n"); + + /* + * Start with id 0 and check if there is no serial0 alias + * which points to device which is compatible with this driver. + * If alias exists then try next free position. + */ + id = 0; + + for (;;) { + dev_info(&pdev->dev, "Checking id %d\n", id); + id = find_next_zero_bit(bitmap, MAX_UART_INSTANCES, id); + + /* No free empty instance */ + if (id == MAX_UART_INSTANCES) { + dev_err(&pdev->dev, "No free ID\n"); + mutex_unlock(&bitmap_lock); + return -EINVAL; + } + + dev_dbg(&pdev->dev, "The empty id is %d\n", id); + /* Check if ID is empty */ + if (!test_and_set_bit(id, bitmap)) { + /* Break the loop if bit is taken */ + dev_dbg(&pdev->dev, + "Selected ID %d allocation passed\n", + id); + break; + } + dev_dbg(&pdev->dev, + "Selected ID %d allocation failed\n", id); + /* if taking bit fails then try next one */ + id++; + } + } + + mutex_unlock(&bitmap_lock); + + return id; +} + /** * cdns_uart_probe - Platform driver probe * @pdev: Pointer to the platform device structure @@ -1417,11 +1459,16 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match); */ static int cdns_uart_probe(struct platform_device *pdev) { - int rc, id, irq; + int rc, irq; struct uart_port *port; struct resource *res; struct cdns_uart *cdns_uart_data; const struct of_device_id *match; + struct uart_driver *cdns_uart_uart_driver; + char *driver_name; +#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE + struct console *cdns_uart_console; +#endif cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), GFP_KERNEL); @@ -1431,6 +1478,63 @@ static int cdns_uart_probe(struct platform_device *pdev) if (!port) return -ENOMEM; + cdns_uart_uart_driver = devm_kzalloc(&pdev->dev, + sizeof(*cdns_uart_uart_driver), + GFP_KERNEL); + if (!cdns_uart_uart_driver) + return -ENOMEM; + + cdns_uart_data->id = cdns_get_id(pdev); + if (cdns_uart_data->id < 0) + return cdns_uart_data->id; + + /* There is a need to use unique driver name */ + driver_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%d", + CDNS_UART_NAME, cdns_uart_data->id); + if (!driver_name) { + rc = -ENOMEM; + goto err_out_id; + } + + cdns_uart_uart_driver->owner = THIS_MODULE; + cdns_uart_uart_driver->driver_name = driver_name; + cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME; + cdns_uart_uart_driver->major = CDNS_UART_MAJOR; + cdns_uart_uart_driver->minor = cdns_uart_data->id; + cdns_uart_uart_driver->nr = 1; + +#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE + cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console), + GFP_KERNEL); + if (!cdns_uart_console) + return -ENOMEM; + + strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME, + sizeof(cdns_uart_console->name)); + cdns_uart_console->index = cdns_uart_data->id; + cdns_uart_console->write = cdns_uart_console_write; + cdns_uart_console->device = uart_console_device; + cdns_uart_console->setup = cdns_uart_console_setup; + cdns_uart_console->flags = CON_PRINTBUFFER; + cdns_uart_console->data = cdns_uart_uart_driver; + cdns_uart_uart_driver->cons = cdns_uart_console; +#endif + + rc = uart_register_driver(cdns_uart_uart_driver); + if (rc < 0) { + dev_err(&pdev->dev, "Failed to register driver\n"); + goto err_out_id; + } + + cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver; + + /* + * Setting up proper name_base needs to be done after uart + * registration because tty_driver structure is not filled. + * name_base is 0 by default. + */ + cdns_uart_uart_driver->tty_driver->name_base = cdns_uart_data->id; + match = of_match_node(cdns_uart_of_match, pdev->dev.of_node); if (match && match->data) { const struct cdns_platform_data *data = match->data; @@ -1446,7 +1550,8 @@ static int cdns_uart_probe(struct platform_device *pdev) } if (IS_ERR(cdns_uart_data->pclk)) { dev_err(&pdev->dev, "pclk clock not found.\n"); - return PTR_ERR(cdns_uart_data->pclk); + rc = PTR_ERR(cdns_uart_data->pclk); + goto err_out_unregister_driver; } cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk"); @@ -1457,13 +1562,14 @@ static int cdns_uart_probe(struct platform_device *pdev) } if (IS_ERR(cdns_uart_data->uartclk)) { dev_err(&pdev->dev, "uart_clk clock not found.\n"); - return PTR_ERR(cdns_uart_data->uartclk); + rc = PTR_ERR(cdns_uart_data->uartclk); + goto err_out_unregister_driver; } rc = clk_prepare_enable(cdns_uart_data->pclk); if (rc) { dev_err(&pdev->dev, "Unable to enable pclk clock.\n"); - return rc; + goto err_out_unregister_driver; } rc = clk_prepare_enable(cdns_uart_data->uartclk); if (rc) { @@ -1490,28 +1596,14 @@ static int cdns_uart_probe(struct platform_device *pdev) &cdns_uart_data->clk_rate_change_nb)) dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); #endif - /* Look for a serialN alias */ - id = of_alias_get_id(pdev->dev.of_node, "serial"); - if (id < 0) - id = 0; - - if (id >= CDNS_UART_NR_PORTS) { - dev_err(&pdev->dev, "Cannot get uart_port structure\n"); - rc = -ENODEV; - goto err_out_notif_unreg; - } /* At this point, we've got an empty uart_port struct, initialize it */ spin_lock_init(&port->lock); - port->membase = NULL; - port->irq = 0; port->type = PORT_UNKNOWN; port->iotype = UPIO_MEM32; port->flags = UPF_BOOT_AUTOCONF; port->ops = &cdns_uart_ops; port->fifosize = CDNS_UART_FIFO_SIZE; - port->line = id; - port->dev = NULL; /* * Register the port. @@ -1538,11 +1630,11 @@ static int cdns_uart_probe(struct platform_device *pdev) * If register_console() don't assign value, then console_port pointer * is cleanup. */ - if (cdns_uart_uart_driver.cons->index == -1) + if (!console_port) console_port = port; #endif - rc = uart_add_one_port(&cdns_uart_uart_driver, port); + rc = uart_add_one_port(cdns_uart_uart_driver, port); if (rc) { dev_err(&pdev->dev, "uart_add_one_port() failed; err=%i\n", rc); @@ -1551,7 +1643,8 @@ static int cdns_uart_probe(struct platform_device *pdev) #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE /* This is not port which is used for console that's why clean it up */ - if (cdns_uart_uart_driver.cons->index == -1) + if (console_port == port && + !(cdns_uart_uart_driver->cons->flags & CON_ENABLED)) console_port = NULL; #endif @@ -1561,7 +1654,6 @@ err_out_pm_disable: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); -err_out_notif_unreg: #ifdef CONFIG_COMMON_CLK clk_notifier_unregister(cdns_uart_data->uartclk, &cdns_uart_data->clk_rate_change_nb); @@ -1570,7 +1662,12 @@ err_out_clk_disable: clk_disable_unprepare(cdns_uart_data->uartclk); err_out_clk_dis_pclk: clk_disable_unprepare(cdns_uart_data->pclk); - +err_out_unregister_driver: + uart_unregister_driver(cdns_uart_data->cdns_uart_driver); +err_out_id: + mutex_lock(&bitmap_lock); + clear_bit(cdns_uart_data->id, bitmap); + mutex_unlock(&bitmap_lock); return rc; } @@ -1591,13 +1688,23 @@ static int cdns_uart_remove(struct platform_device *pdev) clk_notifier_unregister(cdns_uart_data->uartclk, &cdns_uart_data->clk_rate_change_nb); #endif - rc = uart_remove_one_port(&cdns_uart_uart_driver, port); + rc = uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port); port->mapbase = 0; + mutex_lock(&bitmap_lock); + clear_bit(cdns_uart_data->id, bitmap); + mutex_unlock(&bitmap_lock); clk_disable_unprepare(cdns_uart_data->uartclk); clk_disable_unprepare(cdns_uart_data->pclk); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); + +#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE + if (console_port == port) + console_port = NULL; +#endif + + uart_unregister_driver(cdns_uart_data->cdns_uart_driver); return rc; } @@ -1613,28 +1720,14 @@ static struct platform_driver cdns_uart_platform_driver = { static int __init cdns_uart_init(void) { - int retval = 0; - - /* Register the cdns_uart driver with the serial core */ - retval = uart_register_driver(&cdns_uart_uart_driver); - if (retval) - return retval; - /* Register the platform driver */ - retval = platform_driver_register(&cdns_uart_platform_driver); - if (retval) - uart_unregister_driver(&cdns_uart_uart_driver); - - return retval; + return platform_driver_register(&cdns_uart_platform_driver); } static void __exit cdns_uart_exit(void) { /* Unregister the platform driver */ platform_driver_unregister(&cdns_uart_platform_driver); - - /* Unregister the cdns_uart driver */ - uart_unregister_driver(&cdns_uart_uart_driver); } arch_initcall(cdns_uart_init); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index c996b6859c5e..76151c002858 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -118,9 +118,12 @@ void tty_buffer_free_all(struct tty_port *port) struct tty_bufhead *buf = &port->buf; struct tty_buffer *p, *next; struct llist_node *llist; + unsigned int freed = 0; + int still_used; while ((p = buf->head) != NULL) { buf->head = p->next; + freed += p->size; if (p->size > 0) kfree(p); } @@ -132,7 +135,9 @@ void tty_buffer_free_all(struct tty_port *port) buf->head = &buf->sentinel; buf->tail = &buf->sentinel; - atomic_set(&buf->mem_used, 0); + still_used = atomic_xchg(&buf->mem_used, 0); + WARN(still_used != freed, "we still have not freed %d bytes!", + still_used - freed); } /** diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 25d736880013..cb6075096a5b 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -279,7 +279,6 @@ EXPORT_SYMBOL(tty_port_put); * Return a refcount protected tty instance or NULL if the port is not * associated with a tty (eg due to close or hangup) */ - struct tty_struct *tty_port_tty_get(struct tty_port *port) { unsigned long flags; @@ -300,7 +299,6 @@ EXPORT_SYMBOL(tty_port_tty_get); * Associate the port and tty pair. Manages any internal refcounts. * Pass NULL to deassociate a port */ - void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) { unsigned long flags; @@ -343,7 +341,6 @@ out: * * Caller holds tty lock. */ - void tty_port_hangup(struct tty_port *port) { struct tty_struct *tty; @@ -399,7 +396,6 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup); * to hide some internal details. This will eventually become entirely * internal to the tty port. */ - int tty_port_carrier_raised(struct tty_port *port) { if (port->ops->carrier_raised == NULL) @@ -416,7 +412,6 @@ EXPORT_SYMBOL(tty_port_carrier_raised); * to hide some internal details. This will eventually become entirely * internal to the tty port. */ - void tty_port_raise_dtr_rts(struct tty_port *port) { if (port->ops->dtr_rts) @@ -432,7 +427,6 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts); * to hide some internal details. This will eventually become entirely * internal to the tty port. */ - void tty_port_lower_dtr_rts(struct tty_port *port) { if (port->ops->dtr_rts) @@ -464,7 +458,6 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts); * 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, struct tty_struct *tty, struct file *filp) { |