diff options
Diffstat (limited to 'drivers/tty')
54 files changed, 738 insertions, 1084 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b2d760055952..e53d9a512c6d 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -966,9 +966,7 @@ static void rs_throttle(struct tty_struct * tty) struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty)); #endif @@ -991,9 +989,7 @@ static void rs_unthrottle(struct tty_struct * tty) struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty_name(tty, buf), + printk("unthrottle %s: %d....\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty)); #endif @@ -1786,7 +1782,8 @@ static int __exit amiga_serial_remove(struct platform_device *pdev) struct serial_state *state = platform_get_drvdata(pdev); /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - if ((error = tty_unregister_driver(serial_driver))) + error = tty_unregister_driver(serial_driver); + if (error) printk("SERIAL: failed to unregister serial driver (%d)\n", error); put_tty_driver(serial_driver); diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index fd66f57390d0..87f6578c6f4a 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2861,9 +2861,7 @@ static void cy_throttle(struct tty_struct *tty) unsigned long flags; #ifdef CY_DEBUG_THROTTLE - char buf[64]; - - printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf), + printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty), info->line); #endif @@ -2902,10 +2900,8 @@ static void cy_unthrottle(struct tty_struct *tty) unsigned long flags; #ifdef CY_DEBUG_THROTTLE - char buf[64]; - printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n", - tty_name(tty, buf), tty_chars_in_buffer(tty), info->line); + tty_name(tty), tty_chars_in_buffer(tty), info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index 8902f9b4df71..2509d057b99c 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig @@ -42,13 +42,6 @@ config HVC_RTAS help IBM Console device driver which makes use of RTAS -config HVC_BEAT - bool "Toshiba's Beat Hypervisor Console support" - depends on PPC_CELLEB - select HVC_DRIVER - help - Toshiba's Cell Reference Set Beat Console device driver - config HVC_IUCV bool "z/VM IUCV Hypervisor console support (VM only)" depends on S390 diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index 4ca3723b0a3a..6a2702be76d1 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_TILE) += hvc_tile.o obj-$(CONFIG_HVC_DCC) += hvc_dcc.o -obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o obj-$(CONFIG_HVC_IRQ) += hvc_irq.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c deleted file mode 100644 index 1560d235449e..000000000000 --- a/drivers/tty/hvc/hvc_beat.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Beat hypervisor console driver - * - * (C) Copyright 2006 TOSHIBA CORPORATION - * - * This code is based on drivers/char/hvc_rtas.c: - * (C) Copyright IBM Corporation 2001-2005 - * (C) Copyright Red Hat, Inc. 2005 - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/err.h> -#include <linux/string.h> -#include <linux/console.h> -#include <asm/prom.h> -#include <asm/hvconsole.h> -#include <asm/firmware.h> - -#include "hvc_console.h" - -extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *); -extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t); - -struct hvc_struct *hvc_beat_dev = NULL; - -/* bug: only one queue is available regardless of vtermno */ -static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt) -{ - static unsigned char q[sizeof(unsigned long) * 2] - __attribute__((aligned(sizeof(unsigned long)))); - static int qlen = 0; - u64 got; - -again: - if (qlen) { - if (qlen > cnt) { - memcpy(buf, q, cnt); - qlen -= cnt; - memmove(q + cnt, q, qlen); - return cnt; - } else { /* qlen <= cnt */ - int r; - - memcpy(buf, q, qlen); - r = qlen; - qlen = 0; - return r; - } - } - if (beat_get_term_char(vtermno, &got, - ((u64 *)q), ((u64 *)q) + 1) == 0) { - qlen = got; - goto again; - } - return 0; -} - -static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) -{ - unsigned long kb[2]; - int rest, nlen; - - for (rest = cnt; rest > 0; rest -= nlen) { - nlen = (rest > 16) ? 16 : rest; - memcpy(kb, buf, nlen); - beat_put_term_char(vtermno, nlen, kb[0], kb[1]); - buf += nlen; - } - return cnt; -} - -static const struct hv_ops hvc_beat_get_put_ops = { - .get_chars = hvc_beat_get_chars, - .put_chars = hvc_beat_put_chars, -}; - -static int hvc_beat_useit = 1; - -static int hvc_beat_config(char *p) -{ - hvc_beat_useit = simple_strtoul(p, NULL, 0); - return 0; -} - -static int __init hvc_beat_console_init(void) -{ - if (hvc_beat_useit && of_machine_is_compatible("Beat")) { - hvc_instantiate(0, 0, &hvc_beat_get_put_ops); - } - return 0; -} - -/* temp */ -static int __init hvc_beat_init(void) -{ - struct hvc_struct *hp; - - if (!firmware_has_feature(FW_FEATURE_BEAT)) - return -ENODEV; - - hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16); - if (IS_ERR(hp)) - return PTR_ERR(hp); - hvc_beat_dev = hp; - return 0; -} - -static void __exit hvc_beat_exit(void) -{ - if (hvc_beat_dev) - hvc_remove(hvc_beat_dev); -} - -module_init(hvc_beat_init); -module_exit(hvc_beat_exit); - -__setup("hvc_beat=", hvc_beat_config); - -console_initcall(hvc_beat_console_init); diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 4fcec1d793a7..4e9c4cc9e1b5 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -319,7 +319,8 @@ static int hvc_install(struct tty_driver *driver, struct tty_struct *tty) int rc; /* Auto increments kref reference if found. */ - if (!(hp = hvc_get_by_index(tty->index))) + hp = hvc_get_by_index(tty->index); + if (!hp) return -ENODEV; tty->driver_data = hp; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 81ff7e1bfb1a..f7ff97c0ad34 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1044,8 +1044,8 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, * It is possible that the vty-server was removed between the time that * the conn was registered and now. */ - if (!(rc = request_irq(irq, &hvcs_handle_interrupt, - 0, "ibmhvcs", hvcsd))) { + rc = request_irq(irq, &hvcs_handle_interrupt, 0, "ibmhvcs", hvcsd); + if (!rc) { /* * It is possible the vty-server was removed after the irq was * requested but before we have time to enable interrupts. diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 2c34c3249972..c408689a85a9 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2274,7 +2274,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, const unsigned char *dp; char *f; int i; - char buf[64]; char flags = TTY_NORMAL; if (debug & 4) @@ -2296,7 +2295,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, break; default: WARN_ONCE(1, "%s: unknown flag %d\n", - tty_name(tty, buf), flags); + tty_name(tty), flags); break; } } diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index cc57a3a6b02b..85e46422311c 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1179,13 +1179,12 @@ static void n_tty_receive_break(struct tty_struct *tty) static void n_tty_receive_overrun(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; - char buf[64]; ldata->num_overrun++; if (time_after(jiffies, ldata->overrun_time + HZ) || time_after(ldata->overrun_time, jiffies)) { printk(KERN_WARNING "%s: %d input overrun(s)\n", - tty_name(tty, buf), + tty_name(tty), ldata->num_overrun); ldata->overrun_time = jiffies; ldata->num_overrun = 0; @@ -1460,8 +1459,6 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) static void n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag) { - char buf[64]; - switch (flag) { case TTY_BREAK: n_tty_receive_break(tty); @@ -1475,7 +1472,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag) break; default: printk(KERN_ERR "%s: unknown flag %d\n", - tty_name(tty, buf), flag); + tty_name(tty), flag); break; } } diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 74885af8c7bd..80f9de907563 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -140,8 +140,8 @@ static int debug; #define R_FCR 0x0000 /* Flow Control Register */ #define R_IER 0x0004 /* Interrupt Enable Register */ -#define CONFIG_MAGIC 0xEFEFFEFE -#define TOGGLE_VALID 0x0000 +#define NOZOMI_CONFIG_MAGIC 0xEFEFFEFE +#define TOGGLE_VALID 0x0000 /* Definition of interrupt tokens */ #define MDM_DL1 0x0001 @@ -660,9 +660,9 @@ static int nozomi_read_config_table(struct nozomi *dc) read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, sizeof(struct config_table)); - if (dc->config_table.signature != CONFIG_MAGIC) { + if (dc->config_table.signature != NOZOMI_CONFIG_MAGIC) { dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", - dc->config_table.signature, CONFIG_MAGIC); + dc->config_table.signature, NOZOMI_CONFIG_MAGIC); return 0; } diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 5dc9c4bfa66e..748c18f8c8cd 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -508,7 +508,8 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty) int i; cflag = tty->termios.c_cflag; - if (!(port = info->port)) + port = info->port; + if (!port) return; ustcnt = uart->ustcnt; diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 4506e405c8f3..242e796480de 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -85,19 +85,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */ #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) -#ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define CONFIG_SERIAL_DETECT_IRQ 1 -#endif -#ifdef CONFIG_SERIAL_8250_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS 1 -#endif - -/* - * HUB6 is always on. This will be removed once the header - * files have been cleaned. - */ -#define CONFIG_HUB6 1 - #include <asm/serial.h> /* * SERIAL_PORT_DFNS tells us about built-in ports that have no @@ -3548,6 +3535,9 @@ static struct console univ8250_console = { static int __init univ8250_console_init(void) { + if (nr_uarts == 0) + return -ENODEV; + serial8250_isa_init_ports(); register_console(&univ8250_console); return 0; @@ -3578,7 +3568,7 @@ int __init early_serial_setup(struct uart_port *port) { struct uart_port *p; - if (port->line >= ARRAY_SIZE(serial8250_ports)) + if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0) return -ENODEV; serial8250_isa_init_ports(); @@ -3850,7 +3840,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.mapbase = up->port.mapbase; uart->port.mapsize = up->port.mapsize; uart->port.private_data = up->port.private_data; - uart->port.fifosize = up->port.fifosize; uart->tx_loadsz = up->tx_loadsz; uart->capabilities = up->capabilities; uart->port.throttle = up->port.throttle; @@ -3945,6 +3934,9 @@ static int __init serial8250_init(void) { int ret; + if (nr_uarts == 0) + return -ENODEV; + serial8250_isa_init_ports(); printk(KERN_INFO "Serial: 8250/16550 driver, " diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 6c0fd8b9d1c3..771dda29a0f8 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -131,7 +131,7 @@ static void __init init_port(struct earlycon_device *device) serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init early_serial8250_setup(struct earlycon_device *device, +int __init early_serial8250_setup(struct earlycon_device *device, const char *options) { if (!(device->port.membase || device->port.iobase)) diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 7a11fac775c4..4488c2bdb7ba 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -34,6 +34,7 @@ struct mtk8250_data { int line; struct clk *uart_clk; + struct clk *bus_clk; }; static void @@ -115,6 +116,36 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, tty_termios_encode_baud_rate(termios, baud, baud); } +static int mtk8250_runtime_suspend(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + + clk_disable_unprepare(data->uart_clk); + clk_disable_unprepare(data->bus_clk); + + return 0; +} + +static int mtk8250_runtime_resume(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(data->uart_clk); + if (err) { + dev_warn(dev, "Can't enable clock\n"); + return err; + } + + err = clk_prepare_enable(data->bus_clk); + if (err) { + dev_warn(dev, "Can't enable bus clock\n"); + return err; + } + + return 0; +} + static void mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { @@ -130,22 +161,24 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, struct mtk8250_data *data) { - int err; - struct device_node *np = pdev->dev.of_node; - - data->uart_clk = of_clk_get(np, 0); + data->uart_clk = devm_clk_get(&pdev->dev, "baud"); if (IS_ERR(data->uart_clk)) { - dev_warn(&pdev->dev, "Can't get timer clock\n"); - return PTR_ERR(data->uart_clk); + /* + * For compatibility with older device trees try unnamed + * clk when no baud clk can be found. + */ + data->uart_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(data->uart_clk)) { + dev_warn(&pdev->dev, "Can't get uart clock\n"); + return PTR_ERR(data->uart_clk); + } + + return 0; } - err = clk_prepare_enable(data->uart_clk); - if (err) { - dev_warn(&pdev->dev, "Can't prepare clock\n"); - clk_put(data->uart_clk); - return err; - } - p->uartclk = clk_get_rate(data->uart_clk); + data->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(data->bus_clk)) + return PTR_ERR(data->bus_clk); return 0; } @@ -190,19 +223,24 @@ static int mtk8250_probe(struct platform_device *pdev) uart.port.regshift = 2; uart.port.private_data = data; uart.port.set_termios = mtk8250_set_termios; + uart.port.uartclk = clk_get_rate(data->uart_clk); /* Disable Rate Fix function */ writel(0x0, uart.port.membase + (MTK_UART_RATE_FIX << uart.port.regshift)); - data->line = serial8250_register_8250_port(&uart); - if (data->line < 0) - return data->line; - platform_set_drvdata(pdev, data); - pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + err = mtk8250_runtime_resume(&pdev->dev); + if (err) + return err; + } + + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) + return data->line; return 0; } @@ -214,13 +252,13 @@ static int mtk8250_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); serial8250_unregister_port(data->line); - if (!IS_ERR(data->uart_clk)) { - clk_disable_unprepare(data->uart_clk); - clk_put(data->uart_clk); - } pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); + + if (!pm_runtime_status_suspended(&pdev->dev)) + mtk8250_runtime_suspend(&pdev->dev); + return 0; } @@ -244,28 +282,6 @@ static int mtk8250_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM -static int mtk8250_runtime_suspend(struct device *dev) -{ - struct mtk8250_data *data = dev_get_drvdata(dev); - - if (!IS_ERR(data->uart_clk)) - clk_disable_unprepare(data->uart_clk); - - return 0; -} - -static int mtk8250_runtime_resume(struct device *dev) -{ - struct mtk8250_data *data = dev_get_drvdata(dev); - - if (!IS_ERR(data->uart_clk)) - clk_prepare_enable(data->uart_clk); - - return 0; -} -#endif - static const struct dev_pm_ops mtk8250_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume) SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume, @@ -289,6 +305,19 @@ static struct platform_driver mtk8250_platform_driver = { }; module_platform_driver(mtk8250_platform_driver); +static int __init early_mtk8250_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->port.iotype = UPIO_MEM32; + + return early_serial8250_setup(device, NULL); +} + +OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup); + MODULE_AUTHOR("Matthias Brugger"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Mediatek 8250 serial port driver"); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 9289999cb7c6..77c9f5aa8369 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -98,6 +98,7 @@ struct omap8250_priv { struct pm_qos_request pm_qos_request; struct work_struct qos_work; struct uart_8250_dma omap8250_dma; + spinlock_t rx_dma_lock; }; static u32 uart_read(struct uart_8250_port *up, u32 reg) @@ -669,14 +670,21 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir); static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) { + struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; struct dma_tx_state state; int count; + unsigned long flags; dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, dma->rx_size, DMA_FROM_DEVICE); + spin_lock_irqsave(&priv->rx_dma_lock, flags); + + if (!dma->rx_running) + goto unlock; + dma->rx_running = 0; dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); dmaengine_terminate_all(dma->rxchan); @@ -685,6 +693,9 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) tty_insert_flip_string(tty_port, dma->rx_buf, count); p->port.icount.rx += count; +unlock: + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + if (!error) omap_8250_rx_dma(p, 0); @@ -696,28 +707,45 @@ static void __dma_rx_complete(void *param) __dma_rx_do_complete(param, false); } +static void omap_8250_rx_dma_flush(struct uart_8250_port *p) +{ + struct omap8250_priv *priv = p->port.private_data; + struct uart_8250_dma *dma = p->dma; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_dma_lock, flags); + + if (!dma->rx_running) { + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + return; + } + + dmaengine_pause(dma->rxchan); + + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + + __dma_rx_do_complete(p, true); +} + static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) { + struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; + int err = 0; struct dma_async_tx_descriptor *desc; + unsigned long flags; switch (iir & 0x3f) { case UART_IIR_RLSI: /* 8250_core handles errors and break interrupts */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -EIO; case UART_IIR_RX_TIMEOUT: /* * If RCVR FIFO trigger level was not reached, complete the * transfer and let 8250_core copy the remaining data. */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -ETIMEDOUT; case UART_IIR_RDI: /* @@ -729,24 +757,25 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) * the DMA won't do anything soon so we have to cancel the DMA * transfer and purge the FIFO manually. */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -ETIMEDOUT; default: break; } + spin_lock_irqsave(&priv->rx_dma_lock, flags); + if (dma->rx_running) - return 0; + goto out; desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EBUSY; + if (!desc) { + err = -EBUSY; + goto out; + } dma->rx_running = 1; desc->callback = __dma_rx_complete; @@ -758,7 +787,9 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) dma->rx_size, DMA_FROM_DEVICE); dma_async_issue_pending(dma->rxchan); - return 0; +out: + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + return err; } static int omap_8250_tx_dma(struct uart_8250_port *p); @@ -1065,6 +1096,8 @@ static int omap8250_probe(struct platform_device *pdev) priv->latency); INIT_WORK(&priv->qos_work, omap8250_uart_qos_work); + spin_lock_init(&priv->rx_dma_lock); + device_init_wakeup(&pdev->dev, true); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, -1); diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index f8120c1bde14..59a8ad6e7c3e 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1349,7 +1349,7 @@ config SERIAL_ALTERA_UART_CONSOLE config SERIAL_IFX6X60 tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" - depends on GPIOLIB && SPI + depends on GPIOLIB && SPI && HAS_DMA help Support for the IFX6x60 modem devices on Intel MID platforms. @@ -1378,14 +1378,6 @@ config SERIAL_PCH_UART_CONSOLE (the system console is the device which receives all kernel messages and warnings and which allows logins in single user mode). -config SERIAL_MSM_SMD - bool "Enable tty device interface for some SMD ports" - default n - depends on MSM_SMD - help - Enables userspace clients to read and write to some streaming SMD - ports via tty device interface for MSM chipset. - config SERIAL_MXS_AUART depends on ARCH_MXS tristate "MXS AUART support" diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index c3ac3d930b33..432cb6465227 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -79,7 +79,6 @@ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o -obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 0fefdd8931a2..32df2a0cb060 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -387,7 +387,7 @@ console_initcall(altera_jtaguart_console_init); #define ALTERA_JTAGUART_CONSOLE NULL -#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */ +#endif /* CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE */ static struct uart_driver altera_jtaguart_driver = { .owner = THIS_MODULE, diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index b2859fe07e14..fd87a6f574e3 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -493,7 +493,7 @@ console_initcall(altera_uart_console_init); #define ALTERA_UART_CONSOLE NULL -#endif /* CONFIG_ALTERA_UART_CONSOLE */ +#endif /* CONFIG_SERIAL_ALTERA_UART_CONSOLE */ /* * Define the altera_uart UART driver structure. diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 6f5a0720a8c8..6fabc059efed 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -58,7 +58,6 @@ #include <linux/pinctrl/consumer.h> #include <linux/sizes.h> #include <linux/io.h> -#include <linux/workqueue.h> #define UART_NR 14 @@ -157,9 +156,7 @@ struct uart_amba_port { unsigned int lcrh_tx; /* vendor-specific */ unsigned int lcrh_rx; /* vendor-specific */ unsigned int old_cr; /* state during shutdown */ - struct delayed_work tx_softirq_work; bool autorts; - unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */ char type[12]; #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ @@ -1172,15 +1169,14 @@ static void pl011_stop_tx(struct uart_port *port) pl011_dma_tx_stop(uap); } -static bool pl011_tx_chars(struct uart_amba_port *uap); +static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); /* Start TX with programmed I/O only (no DMA) */ static void pl011_start_tx_pio(struct uart_amba_port *uap) { uap->im |= UART011_TXIM; writew(uap->im, uap->port.membase + UART011_IMSC); - if (!uap->tx_irq_seen) - pl011_tx_chars(uap); + pl011_tx_chars(uap, false); } static void pl011_start_tx(struct uart_port *port) @@ -1247,87 +1243,54 @@ __acquires(&uap->port.lock) spin_lock(&uap->port.lock); } -/* - * Transmit a character - * There must be at least one free entry in the TX FIFO to accept the char. - * - * Returns true if the FIFO might have space in it afterwards; - * returns false if the FIFO definitely became full. - */ -static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c) +static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, + bool from_irq) { + if (unlikely(!from_irq) && + readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + return false; /* unable to transmit character */ + writew(c, uap->port.membase + UART01x_DR); uap->port.icount.tx++; - if (likely(uap->tx_irq_seen > 1)) - return true; - - return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF); + return true; } -static bool pl011_tx_chars(struct uart_amba_port *uap) +static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) { struct circ_buf *xmit = &uap->port.state->xmit; - int count; - - if (unlikely(uap->tx_irq_seen < 2)) - /* - * Initial FIFO fill level unknown: we must check TXFF - * after each write, so just try to fill up the FIFO. - */ - count = uap->fifosize; - else /* tx_irq_seen >= 2 */ - /* - * FIFO initially at least half-empty, so we can simply - * write half the FIFO without polling TXFF. - - * Note: the *first* TX IRQ can still race with - * pl011_start_tx_pio(), which can result in the FIFO - * being fuller than expected in that case. - */ - count = uap->fifosize >> 1; - - /* - * If the FIFO is full we're guaranteed a TX IRQ at some later point, - * and can't transmit immediately in any case: - */ - if (unlikely(uap->tx_irq_seen < 2 && - readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)) - return false; + int count = uap->fifosize >> 1; if (uap->port.x_char) { - pl011_tx_char(uap, uap->port.x_char); + if (!pl011_tx_char(uap, uap->port.x_char, from_irq)) + return; uap->port.x_char = 0; --count; } if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { pl011_stop_tx(&uap->port); - goto done; + return; } /* If we are using DMA mode, try to send some characters. */ if (pl011_dma_tx_irq(uap)) - goto done; + return; - while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) { - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - if (uart_circ_empty(xmit)) + do { + if (likely(from_irq) && count-- == 0) break; - } + + if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq)) + break; + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } while (!uart_circ_empty(xmit)); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); - if (uart_circ_empty(xmit)) { + if (uart_circ_empty(xmit)) pl011_stop_tx(&uap->port); - goto done; - } - - if (unlikely(!uap->tx_irq_seen)) - schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout); - -done: - return false; } static void pl011_modem_status(struct uart_amba_port *uap) @@ -1354,28 +1317,6 @@ static void pl011_modem_status(struct uart_amba_port *uap) wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } -static void pl011_tx_softirq(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct uart_amba_port *uap = - container_of(dwork, struct uart_amba_port, tx_softirq_work); - - spin_lock(&uap->port.lock); - while (pl011_tx_chars(uap)) ; - spin_unlock(&uap->port.lock); -} - -static void pl011_tx_irq_seen(struct uart_amba_port *uap) -{ - if (likely(uap->tx_irq_seen > 1)) - return; - - uap->tx_irq_seen++; - if (uap->tx_irq_seen < 2) - /* first TX IRQ */ - cancel_delayed_work(&uap->tx_softirq_work); -} - static irqreturn_t pl011_int(int irq, void *dev_id) { struct uart_amba_port *uap = dev_id; @@ -1414,10 +1355,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (status & (UART011_DSRMIS|UART011_DCDMIS| UART011_CTSMIS|UART011_RIMIS)) pl011_modem_status(uap); - if (status & UART011_TXIS) { - pl011_tx_irq_seen(uap); - pl011_tx_chars(uap); - } + if (status & UART011_TXIS) + pl011_tx_chars(uap, true); if (pass_counter-- == 0) break; @@ -1697,8 +1636,6 @@ static void pl011_shutdown(struct uart_port *port) container_of(port, struct uart_amba_port, port); unsigned int cr; - cancel_delayed_work_sync(&uap->tx_softirq_work); - /* * disable all interrupts */ @@ -2245,7 +2182,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = i; - INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq); /* Ensure interrupts from this UART are masked and cleared */ writew(0, uap->port.membase + UART011_IMSC); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 27dade29646b..b1fcddd6652a 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -165,6 +165,7 @@ struct atmel_uart_port { struct tasklet_struct tasklet; unsigned int irq_status; unsigned int irq_status_prev; + unsigned int status_change; struct circ_buf rx_ring; @@ -1177,6 +1178,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending, if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) { atmel_port->irq_status = status; + atmel_port->status_change = atmel_port->irq_status ^ + atmel_port->irq_status_prev; + atmel_port->irq_status_prev = status; tasklet_schedule(&atmel_port->tasklet); } } @@ -1523,17 +1527,14 @@ static void atmel_tasklet_func(unsigned long data) { struct uart_port *port = (struct uart_port *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status; - unsigned int status_change; + unsigned int status = atmel_port->irq_status; + unsigned int status_change = atmel_port->status_change; /* The interrupt handler does not take the lock */ spin_lock(&port->lock); atmel_port->schedule_tx(port); - status = atmel_port->irq_status; - status_change = status ^ atmel_port->irq_status_prev; - if (status_change & (ATMEL_US_RI | ATMEL_US_DSR | ATMEL_US_DCD | ATMEL_US_CTS)) { /* TODO: All reads to CSR will clear these interrupts! */ @@ -1548,7 +1549,7 @@ static void atmel_tasklet_func(unsigned long data) wake_up_interruptible(&port->state->port.delta_msr_wait); - atmel_port->irq_status_prev = status; + atmel_port->status_change = 0; } atmel_port->schedule_rx(port); diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 155781ece050..ae3cf94b146b 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -74,8 +74,8 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart); static void bfin_serial_reset_irda(struct uart_port *port); -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +#if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) static unsigned int bfin_serial_get_mctrl(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; @@ -110,7 +110,7 @@ static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) struct bfin_serial_port *uart = dev_id; struct uart_port *uport = &uart->port; unsigned int status = bfin_serial_get_mctrl(uport); -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS UART_CLEAR_SCTS(uart); if (uport->hw_stopped) { @@ -700,7 +700,7 @@ static int bfin_serial_startup(struct uart_port *port) # endif #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (uart->cts_pin >= 0) { if (request_irq(gpio_to_irq(uart->cts_pin), bfin_serial_mctrl_cts_int, @@ -718,7 +718,7 @@ static int bfin_serial_startup(struct uart_port *port) gpio_direction_output(uart->rts_pin, 0); } #endif -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0) { if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int, 0, "BFIN_UART_MODEM_STATUS", uart)) { @@ -766,13 +766,13 @@ static void bfin_serial_shutdown(struct uart_port *port) free_irq(uart->tx_irq, uart); #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (uart->cts_pin >= 0) free_irq(gpio_to_irq(uart->cts_pin), uart); if (uart->rts_pin >= 0) gpio_free(uart->rts_pin); #endif -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0) free_irq(uart->status_irq, uart); #endif @@ -788,7 +788,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int ier, lcr = 0; unsigned long timeout; -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (old == NULL && uart->cts_pin != -1) termios->c_cflag |= CRTSCTS; else if (uart->cts_pin == -1) @@ -1110,8 +1110,8 @@ bfin_serial_console_setup(struct console *co, char *options) int baud = 57600; int bits = 8; int parity = 'n'; -# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +# if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) int flow = 'r'; # else int flow = 'n'; @@ -1322,8 +1322,8 @@ static int bfin_serial_probe(struct platform_device *pdev) init_timer(&(uart->rx_dma_timer)); #endif -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +#if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res == NULL) uart->cts_pin = -1; diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 0c1825b0b41d..3e4470af5c50 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -56,10 +56,6 @@ static char *serial_version = "$Revision: 1.25 $"; #error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" #endif -#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G) -#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G" -#endif - /* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h @@ -455,30 +451,6 @@ static struct e100_serial rs_table[] = { static struct fast_timer fast_timers[NR_PORTS]; #endif -#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY -#define PROCSTAT(x) x -struct ser_statistics_type { - int overrun_cnt; - int early_errors_cnt; - int ser_ints_ok_cnt; - int errors_cnt; - unsigned long int processing_flip; - unsigned long processing_flip_still_room; - unsigned long int timeout_flush_cnt; - int rx_dma_ints; - int tx_dma_ints; - int rx_tot; - int tx_tot; -}; - -static struct ser_statistics_type ser_stat[NR_PORTS]; - -#else - -#define PROCSTAT(x) - -#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */ - /* RS-485 */ #if defined(CONFIG_ETRAX_RS485) #ifdef CONFIG_ETRAX_FAST_TIMER @@ -487,9 +459,6 @@ static struct fast_timer fast_timers_rs485[NR_PORTS]; #if defined(CONFIG_ETRAX_RS485_ON_PA) static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT; -#endif #endif /* Info and macros needed for each ports extra control/status signals. */ @@ -739,10 +708,10 @@ static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF}; defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \ defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \ defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED) -#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED +#define ETRAX_SERX_DTR_RI_DSR_CD_MIXED #endif -#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED +#ifdef ETRAX_SERX_DTR_RI_DSR_CD_MIXED /* The pins can be mixed on PA and PB */ #define CONTROL_PINS_PORT_NOT_USED(line) \ &dummy_ser[line], &dummy_ser[line], \ @@ -835,7 +804,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = #endif } }; -#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ +#else /* ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ /* All pins are on either PA or PB for each serial port */ #define CONTROL_PINS_PORT_NOT_USED(line) \ @@ -917,7 +886,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = #endif } }; -#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ +#endif /* !ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ #define E100_RTS_MASK 0x20 #define E100_CTS_MASK 0x40 @@ -1367,16 +1336,6 @@ e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r) #if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - rs485_port_g_bit, 1); -#endif -#if defined(CONFIG_ETRAX_RS485_LTC1387) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1); - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1); -#endif info->rs485 = *r; @@ -1676,7 +1635,8 @@ alloc_recv_buffer(unsigned int size) { struct etrax_recv_buffer *buffer; - if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) + buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC); + if (!buffer) return NULL; buffer->next = NULL; @@ -1712,7 +1672,8 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl { struct etrax_recv_buffer *buffer; if (info->uses_dma_in) { - if (!(buffer = alloc_recv_buffer(4))) + buffer = alloc_recv_buffer(4); + if (!buffer) return 0; buffer->length = 1; @@ -1750,7 +1711,8 @@ static unsigned int handle_descr_data(struct e100_serial *info, append_recv_buffer(info, buffer); - if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE); + if (!buffer) panic("%s: Failed to allocate memory for receive buffer!\n", __func__); descr->buf = virt_to_phys(buffer->buffer); @@ -1841,7 +1803,6 @@ static void receive_chars_dma(struct e100_serial *info) */ unsigned char data = info->ioport[REG_DATA]; - PROCSTAT(ser_stat[info->line].errors_cnt++); DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", ((rstat & SER_ERROR_MASK) << 8) | data); @@ -1867,7 +1828,8 @@ static int start_recv_dma(struct e100_serial *info) /* Set up the receiving descriptors */ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { - if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE); + if (!buffer) panic("%s: Failed to allocate memory for receive buffer!\n", __func__); descr[i].ctrl = d_int; @@ -1943,7 +1905,6 @@ tr_interrupt(int irq, void *dev_id) /* Read jiffies_usec first, * we want this time to be as late as possible */ - PROCSTAT(ser_stat[info->line].tx_dma_ints++); info->last_tx_active_usec = GET_JIFFIES_USEC(); info->last_tx_active = jiffies; transmit_chars_dma(info); @@ -2022,7 +1983,6 @@ static int force_eop_if_needed(struct e100_serial *info) */ if (!info->forced_eop) { info->forced_eop = 1; - PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line)); FORCE_EOP(info); } @@ -2374,7 +2334,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info) DEBUG_LOG(info->line, "#iERR s d %04X\n", ((rstat & SER_ERROR_MASK) << 8) | data); } - PROCSTAT(ser_stat[info->line].early_errors_cnt++); } else { /* It was a valid byte, now let the DMA do the rest */ unsigned long curr_time_u = GET_JIFFIES_USEC(); unsigned long curr_time = jiffies; @@ -2407,7 +2366,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info) DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line)); info->break_detected_cnt = 0; - PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); } /* Restarting the DMA never hurts */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); @@ -2867,19 +2825,6 @@ change_speed(struct e100_serial *info) *R_SERIAL_PRESCALE = divisor; info->baud = SERIAL_PRESCALE_BASE/divisor; } -#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED - else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 && - info->custom_divisor == 1) || - (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ && - info->custom_divisor == 8)) { - /* ext_clk selected */ - alt_source = - IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) | - IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern); - DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8)); - info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8; - } -#endif else { /* Bad baudbase, we don't support using timer0 @@ -3216,9 +3161,7 @@ rs_throttle(struct tty_struct * tty) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %lu....\n", tty_name(tty, buf), + printk("throttle %s: %lu....\n", tty_name(tty), (unsigned long)tty->ldisc.chars_in_buffer(tty)); #endif DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty))); @@ -3238,9 +3181,7 @@ rs_unthrottle(struct tty_struct * tty) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %lu....\n", tty_name(tty, buf), + printk("unthrottle %s: %lu....\n", tty_name(tty), (unsigned long)tty->ldisc.chars_in_buffer(tty)); #endif DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty))); @@ -3725,16 +3666,6 @@ rs_close(struct tty_struct *tty, struct file * filp) #if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - rs485_port_g_bit, 0); -#endif -#if defined(CONFIG_ETRAX_RS485_LTC1387) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0); - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0); -#endif } #endif @@ -4263,15 +4194,6 @@ static int __init rs_init(void) return -EBUSY; } #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit, - rs485_port_g_bit)) { - printk(KERN_ERR "ETRAX100LX serial: Could not allocate " - "RS485 pin\n"); - put_tty_driver(driver); - return -EBUSY; - } -#endif #endif /* Initialize the tty_driver structure */ diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 45fc323b95e6..ffc7cb2585a6 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1504,7 +1504,8 @@ static int icom_probe(struct pci_dev *dev, return retval; } - if ( (retval = pci_request_regions(dev, "icom"))) { + retval = pci_request_regions(dev, "icom"); + if (retval) { dev_err(&dev->dev, "pci_request_regions FAILED\n"); pci_disable_device(dev); return retval; @@ -1512,7 +1513,8 @@ static int icom_probe(struct pci_dev *dev, pci_set_master(dev); - if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { + retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg); + if (retval) { dev_err(&dev->dev, "PCI Config read FAILED\n"); return retval; } @@ -1556,9 +1558,8 @@ static int icom_probe(struct pci_dev *dev, } /* save off irq and request irq line */ - if ( (retval = request_irq(dev->irq, icom_interrupt, - IRQF_SHARED, ICOM_DRIVER_NAME, - (void *) icom_adapter))) { + retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter); + if (retval) { goto probe_exit2; } diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 590390970996..536a33b99be9 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -1175,7 +1175,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_spi_reset_interrupt, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, - (void *)ifx_dev); + ifx_dev); if (ret) { dev_err(&spi->dev, "Unable to get irq %x\n", gpio_to_irq(ifx_dev->gpio.reset_out)); @@ -1185,9 +1185,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = ifx_spi_reset(ifx_dev); ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy), - ifx_spi_srdy_interrupt, - IRQF_TRIGGER_RISING, DRVNAME, - (void *)ifx_dev); + ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME, + ifx_dev); if (ret) { dev_err(&spi->dev, "Unable to get irq %x", gpio_to_irq(ifx_dev->gpio.srdy)); @@ -1212,7 +1211,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) return 0; error_ret7: - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev); error_ret6: gpio_free(ifx_dev->gpio.srdy); error_ret5: @@ -1243,8 +1242,8 @@ static int ifx_spi_spi_remove(struct spi_device *spi) /* stop activity */ tasklet_kill(&ifx_dev->io_work_tasklet); /* free irq */ - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); - free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev); gpio_free(ifx_dev->gpio.srdy); gpio_free(ifx_dev->gpio.mrdy); @@ -1381,7 +1380,7 @@ static void __exit ifx_spi_exit(void) /* unregister */ tty_unregister_driver(tty_drv); put_tty_driver(tty_drv); - spi_unregister_driver((void *)&ifx_spi_driver); + spi_unregister_driver(&ifx_spi_driver); unregister_reboot_notifier(&ifx_modem_reboot_notifier_block); } @@ -1420,7 +1419,7 @@ static int __init ifx_spi_init(void) goto err_free_tty; } - result = spi_register_driver((void *)&ifx_spi_driver); + result = spi_register_driver(&ifx_spi_driver); if (result) { pr_err("%s: spi_register_driver failed(%d)", DRVNAME, result); @@ -1436,7 +1435,7 @@ static int __init ifx_spi_init(void) return 0; err_unreg_spi: - spi_unregister_driver((void *)&ifx_spi_driver); + spi_unregister_driver(&ifx_spi_driver); err_unreg_tty: tty_unregister_driver(tty_drv); err_free_tty: diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index c8cfa0637128..91e36bcfde74 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -239,7 +239,7 @@ static struct imx_uart_data imx_uart_devdata[] = { }, }; -static struct platform_device_id imx_uart_devtype[] = { +static const struct platform_device_id imx_uart_devtype[] = { { .name = "imx1-uart", .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART], @@ -853,7 +853,7 @@ static void imx_break_ctl(struct uart_port *port, int break_state) #define TXTL 2 /* reset default */ #define RXTL 1 /* reset default */ -static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) +static void imx_setup_ufcr(struct imx_port *sport, unsigned int mode) { unsigned int val; @@ -861,7 +861,6 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); val |= TXTL << UFCR_TXTL_SHF | RXTL; writel(val, sport->port.membase + UFCR); - return 0; } #define RX_BUF_SIZE (PAGE_SIZE) @@ -1114,6 +1113,12 @@ static int imx_startup(struct uart_port *port) writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); + /* Can we enable the DMA support? */ + if (is_imx6q_uart(sport) && !uart_console(port) && + !sport->dma_is_inited) + imx_uart_dma_init(sport); + + spin_lock_irqsave(&sport->port.lock, flags); /* Reset fifo's and state machines */ i = 100; @@ -1124,13 +1129,6 @@ static int imx_startup(struct uart_port *port) while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) udelay(1); - /* Can we enable the DMA support? */ - if (is_imx6q_uart(sport) && !uart_console(port) && - !sport->dma_is_inited) - imx_uart_dma_init(sport); - - spin_lock_irqsave(&sport->port.lock, flags); - /* * Finally, clear and enable interrupts */ diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c index abd7ea26ed9a..27b5fefac171 100644 --- a/drivers/tty/serial/ioc3_serial.c +++ b/drivers/tty/serial/ioc3_serial.c @@ -2137,7 +2137,8 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) /* register port with the serial core */ - if ((ret = ioc3_serial_core_attach(is, idd))) + ret = ioc3_serial_core_attach(is, idd); + if (ret) goto out4; Num_of_ioc3_cards++; diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index aa28209f44c1..e5c42fef69d2 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -1011,7 +1011,8 @@ static irqreturn_t ioc4_intr(int irq, void *arg) */ for (xx = 0; xx < num_intrs; xx++) { intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx]; - if ((this_mir = this_ir & intr_info->sd_bits)) { + this_mir = this_ir & intr_info->sd_bits; + if (this_mir) { /* Disable owned interrupts, call handler */ handled++; write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC, @@ -2865,10 +2866,12 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) /* register port with the serial core - 1 rs232, 1 rs422 */ - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232))) + ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232); + if (ret) goto out4; - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422))) + ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422); + if (ret) goto out5; Num_of_ioc4_cards++; diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 129dc5be6028..117df151627d 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -173,18 +173,18 @@ static int kgdb_nmi_poll_one_knock(void) bool kgdb_nmi_poll_knock(void) { if (kgdb_nmi_knock < 0) - return 1; + return true; while (1) { int ret; ret = kgdb_nmi_poll_one_knock(); if (ret == NO_POLL_CHAR) - return 0; + return false; else if (ret == 1) break; } - return 1; + return true; } /* diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index a9b0ab38a68c..02eb32217685 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -597,7 +597,7 @@ console_initcall(mcf_console_init); #define MCF_CONSOLE NULL /****************************************************************************/ -#endif /* CONFIG_MCF_CONSOLE */ +#endif /* CONFIG_SERIAL_MCF_CONSOLE */ /****************************************************************************/ /* diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 67c036702629..0fc83c962d10 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -370,7 +370,7 @@ static int meson_uart_verify_port(struct uart_port *port, static void meson_uart_release_port(struct uart_port *port) { if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); + devm_iounmap(port->dev, port->membase); port->membase = NULL; } } diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 1589f17c1fca..6fc07eb9d74e 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -405,7 +405,7 @@ static struct psc_ops mpc5200b_psc_ops = { .get_mr1 = mpc52xx_psc_get_mr1, }; -#endif /* CONFIG_MPC52xx */ +#endif /* CONFIG_PPC_MPC52xx */ #ifdef CONFIG_PPC_MPC512x #define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index 856fd5a5fa3c..82bb6d1fe23b 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -913,7 +913,8 @@ static int mpsc_make_ready(struct mpsc_port_info *pi) if (!pi->ready) { mpsc_init_hw(pi); - if ((rc = mpsc_alloc_ring_mem(pi))) + rc = mpsc_alloc_ring_mem(pi); + if (rc) return rc; mpsc_init_rings(pi); pi->ready = 1; @@ -1895,7 +1896,8 @@ static int mpsc_shared_drv_probe(struct platform_device *dev) int rc = -ENODEV; if (dev->id == 0) { - if (!(rc = mpsc_shared_map_regs(dev))) { + rc = mpsc_shared_map_regs(dev); + if (!rc) { pdata = (struct mpsc_shared_pdata *) dev_get_platdata(&dev->dev); @@ -2081,14 +2083,16 @@ static int mpsc_drv_probe(struct platform_device *dev) if (dev->id < MPSC_NUM_CTLRS) { pi = &mpsc_ports[dev->id]; - if (!(rc = mpsc_drv_map_regs(pi, dev))) { + rc = mpsc_drv_map_regs(pi, dev); + if (!rc) { mpsc_drv_get_platform_data(pi, dev, dev->id); pi->port.dev = &dev->dev; - if (!(rc = mpsc_make_ready(pi))) { + rc = mpsc_make_ready(pi); + if (!rc) { spin_lock_init(&pi->tx_lock); - if (!(rc = uart_add_one_port(&mpsc_reg, - &pi->port))) { + rc = uart_add_one_port(&mpsc_reg, &pi->port); + if (!rc) { rc = 0; } else { mpsc_release_port((struct uart_port *) @@ -2136,9 +2140,12 @@ static int __init mpsc_drv_init(void) memset(mpsc_ports, 0, sizeof(mpsc_ports)); memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); - if (!(rc = uart_register_driver(&mpsc_reg))) { - if (!(rc = platform_driver_register(&mpsc_shared_driver))) { - if ((rc = platform_driver_register(&mpsc_driver))) { + rc = uart_register_driver(&mpsc_reg); + if (!rc) { + rc = platform_driver_register(&mpsc_shared_driver); + if (!rc) { + rc = platform_driver_register(&mpsc_driver); + if (rc) { platform_driver_unregister(&mpsc_shared_driver); uart_unregister_driver(&mpsc_reg); } diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c deleted file mode 100644 index 1238ac370bff..000000000000 --- a/drivers/tty/serial/msm_smd_tty.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. - * Author: Brian Swetland <swetland@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/cdev.h> -#include <linux/device.h> -#include <linux/wait.h> - -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> - -#include <mach/msm_smd.h> - -#define MAX_SMD_TTYS 32 - -struct smd_tty_info { - struct tty_port port; - smd_channel_t *ch; -}; - -struct smd_tty_channel_desc { - int id; - const char *name; -}; - -static struct smd_tty_info smd_tty[MAX_SMD_TTYS]; - -static const struct smd_tty_channel_desc smd_default_tty_channels[] = { - { .id = 0, .name = "SMD_DS" }, - { .id = 27, .name = "SMD_GPSNMEA" }, -}; - -static const struct smd_tty_channel_desc *smd_tty_channels = - smd_default_tty_channels; -static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels); - -static void smd_tty_notify(void *priv, unsigned event) -{ - unsigned char *ptr; - int avail; - struct smd_tty_info *info = priv; - struct tty_struct *tty; - - if (event != SMD_EVENT_DATA) - return; - - tty = tty_port_tty_get(&info->port); - if (!tty) - return; - - for (;;) { - if (test_bit(TTY_THROTTLED, &tty->flags)) - break; - avail = smd_read_avail(info->ch); - if (avail == 0) - break; - - avail = tty_prepare_flip_string(&info->port, &ptr, avail); - - if (smd_read(info->ch, ptr, avail) != avail) { - /* shouldn't be possible since we're in interrupt - ** context here and nobody else could 'steal' our - ** characters. - */ - pr_err("OOPS - smd_tty_buffer mismatch?!"); - } - - tty_flip_buffer_push(&info->port); - } - - /* XXX only when writable and necessary */ - tty_wakeup(tty); - tty_kref_put(tty); -} - -static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty) -{ - struct smd_tty_info *info = container_of(tport, struct smd_tty_info, - port); - int i, res = 0; - const char *name = NULL; - - for (i = 0; i < smd_tty_channels_len; i++) { - if (smd_tty_channels[i].id == tty->index) { - name = smd_tty_channels[i].name; - break; - } - } - if (!name) - return -ENODEV; - - if (info->ch) - smd_kick(info->ch); - else - res = smd_open(name, &info->ch, info, smd_tty_notify); - - if (!res) - tty->driver_data = info; - - return res; -} - -static void smd_tty_port_shutdown(struct tty_port *tport) -{ - struct smd_tty_info *info = container_of(tport, struct smd_tty_info, - port); - - if (info->ch) { - smd_close(info->ch); - info->ch = 0; - } -} - -static int smd_tty_open(struct tty_struct *tty, struct file *f) -{ - struct smd_tty_info *info = smd_tty + tty->index; - - return tty_port_open(&info->port, tty, f); -} - -static void smd_tty_close(struct tty_struct *tty, struct file *f) -{ - struct smd_tty_info *info = tty->driver_data; - - tty_port_close(&info->port, tty, f); -} - -static int smd_tty_write(struct tty_struct *tty, - const unsigned char *buf, int len) -{ - struct smd_tty_info *info = tty->driver_data; - int avail; - - /* if we're writing to a packet channel we will - ** never be able to write more data than there - ** is currently space for - */ - avail = smd_write_avail(info->ch); - if (len > avail) - len = avail; - - return smd_write(info->ch, buf, len); -} - -static int smd_tty_write_room(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - return smd_write_avail(info->ch); -} - -static int smd_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - return smd_read_avail(info->ch); -} - -static void smd_tty_unthrottle(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - smd_kick(info->ch); -} - -static const struct tty_port_operations smd_tty_port_ops = { - .shutdown = smd_tty_port_shutdown, - .activate = smd_tty_port_activate, -}; - -static const struct tty_operations smd_tty_ops = { - .open = smd_tty_open, - .close = smd_tty_close, - .write = smd_tty_write, - .write_room = smd_tty_write_room, - .chars_in_buffer = smd_tty_chars_in_buffer, - .unthrottle = smd_tty_unthrottle, -}; - -static struct tty_driver *smd_tty_driver; - -static int __init smd_tty_init(void) -{ - int ret, i; - - smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); - if (smd_tty_driver == 0) - return -ENOMEM; - - smd_tty_driver->driver_name = "smd_tty_driver"; - smd_tty_driver->name = "smd"; - smd_tty_driver->major = 0; - smd_tty_driver->minor_start = 0; - smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - smd_tty_driver->subtype = SERIAL_TYPE_NORMAL; - smd_tty_driver->init_termios = tty_std_termios; - smd_tty_driver->init_termios.c_iflag = 0; - smd_tty_driver->init_termios.c_oflag = 0; - smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - smd_tty_driver->init_termios.c_lflag = 0; - smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(smd_tty_driver, &smd_tty_ops); - - ret = tty_register_driver(smd_tty_driver); - if (ret) - return ret; - - for (i = 0; i < smd_tty_channels_len; i++) { - struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port; - tty_port_init(port); - port->ops = &smd_tty_port_ops; - tty_port_register_device(port, smd_tty_driver, - smd_tty_channels[i].id, NULL); - } - - return 0; -} - -module_init(smd_tty_init); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index f7e5825b55ab..13cf7738fbdc 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -169,7 +169,7 @@ struct mxs_auart_port { bool ms_irq_enabled; }; -static struct platform_device_id mxs_auart_devtype[] = { +static const struct platform_device_id mxs_auart_devtype[] = { { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART }, { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART }, { /* sentinel */ } diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 137381e649e5..28b9b4789bbf 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -188,7 +188,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev) { struct uart_8250_port port8250; memset(&port8250, 0, sizeof(port8250)); - port.type = port_type; port8250.port = port; if (port.fifosize) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index a0ae942d9562..67d0c213b1c7 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -348,7 +348,7 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) s3c24xx_serial_start_tx_dma(ourport, count); } -void s3c24xx_serial_start_tx(struct uart_port *port) +static void s3c24xx_serial_start_tx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); struct circ_buf *xmit = &port->state->xmit; @@ -2337,7 +2337,7 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { #define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL #endif -static struct platform_device_id s3c24xx_serial_driver_ids[] = { +static const struct platform_device_id s3c24xx_serial_driver_ids[] = { { .name = "s3c2410-uart", .driver_data = S3C2410_SERIAL_DRV_DATA, diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 1d5ea3964ee5..3b63f103f0c9 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -131,8 +131,8 @@ struct tegra_uart_port { struct dma_async_tx_descriptor *rx_dma_desc; dma_cookie_t tx_cookie; dma_cookie_t rx_cookie; - int tx_bytes_requested; - int rx_bytes_requested; + unsigned int tx_bytes_requested; + unsigned int rx_bytes_requested; }; static void tegra_uart_start_next_tx(struct tegra_uart_port *tup); @@ -234,6 +234,22 @@ static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl) tup->lcr_shadow = lcr; } +/** + * tegra_uart_wait_cycle_time: Wait for N UART clock periods + * + * @tup: Tegra serial port data structure. + * @cycles: Number of clock periods to wait. + * + * Tegra UARTs are clocked at 16X the baud/bit rate and hence the UART + * clock speed is 16X the current baud rate. + */ +static void tegra_uart_wait_cycle_time(struct tegra_uart_port *tup, + unsigned int cycles) +{ + if (tup->current_baud) + udelay(DIV_ROUND_UP(cycles * 1000000, tup->current_baud * 16)); +} + /* Wait for a symbol-time. */ static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup, unsigned int syms) @@ -263,8 +279,12 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) /* Dummy read to ensure the write is posted */ tegra_uart_read(tup, UART_SCR); - /* Wait for the flush to propagate. */ - tegra_uart_wait_sym_time(tup, 1); + /* + * For all tegra devices (up to t210), there is a hardware issue that + * requires software to wait for 32 UART clock periods for the flush + * to propagate, otherwise data could be lost. + */ + tegra_uart_wait_cycle_time(tup, 32); } static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) @@ -388,9 +408,9 @@ static void tegra_uart_tx_dma_complete(void *args) struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; unsigned long flags; - int count; + unsigned int count; - dmaengine_tx_status(tup->tx_dma_chan, tup->rx_cookie, &state); + dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); count = tup->tx_bytes_requested - state.residue; async_tx_ack(tup->tx_dma_desc); spin_lock_irqsave(&tup->uport.lock, flags); @@ -480,7 +500,7 @@ static void tegra_uart_stop_tx(struct uart_port *u) struct tegra_uart_port *tup = to_tegra_uport(u); struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; - int count; + unsigned int count; if (tup->tx_in_progress != TEGRA_UART_TX_DMA) return; @@ -530,10 +550,15 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, } static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, - struct tty_port *tty, int count) + struct tty_port *tty, + unsigned int count) { int copied; + /* If count is zero, then there is no data to be copied */ + if (!count) + return; + tup->uport.icount.rx += count; if (!tty) { dev_err(tup->uport.dev, "No tty port\n"); @@ -555,21 +580,30 @@ static void tegra_uart_rx_dma_complete(void *args) { struct tegra_uart_port *tup = args; struct uart_port *u = &tup->uport; - int count = tup->rx_bytes_requested; + unsigned int count = tup->rx_bytes_requested; struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); struct tty_port *port = &u->state->port; unsigned long flags; + struct dma_tx_state state; + enum dma_status status; - async_tx_ack(tup->rx_dma_desc); spin_lock_irqsave(&u->lock, flags); + status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + + if (status == DMA_IN_PROGRESS) { + dev_dbg(tup->uport.dev, "RX DMA is in progress\n"); + goto done; + } + + async_tx_ack(tup->rx_dma_desc); + /* Deactivate flow control to stop sender */ if (tup->rts_active) set_rts(tup, false); /* If we are here, DMA is stopped */ - if (count) - tegra_uart_copy_rx_to_tty(tup, port, count); + tegra_uart_copy_rx_to_tty(tup, port, count); tegra_uart_handle_rx_pio(tup, port); if (tty) { @@ -584,6 +618,7 @@ static void tegra_uart_rx_dma_complete(void *args) if (tup->rts_active) set_rts(tup, true); +done: spin_unlock_irqrestore(&u->lock, flags); } @@ -594,7 +629,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup, struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); struct tty_port *port = &tup->uport.state->port; struct uart_port *u = &tup->uport; - int count; + unsigned int count; /* Deactivate flow control to stop sender */ if (tup->rts_active) @@ -606,8 +641,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup, count = tup->rx_bytes_requested - state.residue; /* If we are here, DMA is stopped */ - if (count) - tegra_uart_copy_rx_to_tty(tup, port, count); + tegra_uart_copy_rx_to_tty(tup, port, count); tegra_uart_handle_rx_pio(tup, port); if (tty) { @@ -865,6 +899,16 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B; tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); + /* Dummy read to ensure the write is posted */ + tegra_uart_read(tup, UART_SCR); + + /* + * For all tegra devices (up to t210), there is a hardware issue that + * requires software to wait for 3 UART clock periods after enabling + * the TX fifo, otherwise data could be lost. + */ + tegra_uart_wait_cycle_time(tup, 3); + /* * Initialize the UART with default configuration * (115200, N, 8, 1) so that the receive DMA buffer may be @@ -905,6 +949,28 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) return 0; } +static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, + bool dma_to_memory) +{ + if (dma_to_memory) { + dmaengine_terminate_all(tup->rx_dma_chan); + dma_release_channel(tup->rx_dma_chan); + dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, + tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); + tup->rx_dma_chan = NULL; + tup->rx_dma_buf_phys = 0; + tup->rx_dma_buf_virt = NULL; + } else { + dmaengine_terminate_all(tup->tx_dma_chan); + dma_release_channel(tup->tx_dma_chan); + dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); + tup->tx_dma_chan = NULL; + tup->tx_dma_buf_phys = 0; + tup->tx_dma_buf_virt = NULL; + } +} + static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, bool dma_to_memory) { @@ -937,6 +1003,11 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, dma_phys = dma_map_single(tup->uport.dev, tup->uport.state->xmit.buf, UART_XMIT_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(tup->uport.dev, dma_phys)) { + dev_err(tup->uport.dev, "dma_map_single tx failed\n"); + dma_release_channel(dma_chan); + return -ENOMEM; + } dma_buf = tup->uport.state->xmit.buf; } @@ -969,33 +1040,10 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, return 0; scrub: - dma_release_channel(dma_chan); + tegra_uart_dma_channel_free(tup, dma_to_memory); return ret; } -static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, - bool dma_to_memory) -{ - struct dma_chan *dma_chan; - - if (dma_to_memory) { - dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, - tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); - dma_chan = tup->rx_dma_chan; - tup->rx_dma_chan = NULL; - tup->rx_dma_buf_phys = 0; - tup->rx_dma_buf_virt = NULL; - } else { - dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, - UART_XMIT_SIZE, DMA_TO_DEVICE); - dma_chan = tup->tx_dma_chan; - tup->tx_dma_chan = NULL; - tup->tx_dma_buf_phys = 0; - tup->tx_dma_buf_virt = NULL; - } - dma_release_channel(dma_chan); -} - static int tegra_uart_startup(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); @@ -1060,8 +1108,6 @@ static void tegra_uart_shutdown(struct uart_port *u) tegra_uart_dma_channel_free(tup, true); tegra_uart_dma_channel_free(tup, false); free_irq(u->irq, tup); - - tegra_uart_flush_buffer(u); } static void tegra_uart_enable_ms(struct uart_port *u) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0b7bb12dfc68..eec067d8eedb 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -894,12 +894,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, * need to rate-limit; it's CAP_SYS_ADMIN only. */ if (uport->flags & UPF_SPD_MASK) { - char buf[64]; - dev_notice(uport->dev, "%s sets custom speed on %s. This is deprecated.\n", current->comm, - tty_name(port->tty, buf)); + tty_name(port->tty)); } uart_change_speed(tty, state, NULL); } diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e7d6566fafaf..b74a644e4b04 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -81,7 +81,8 @@ struct sci_port { /* Platform configuration */ struct plat_sci_port *cfg; - int overrun_bit; + unsigned int overrun_reg; + unsigned int overrun_mask; unsigned int error_mask; unsigned int sampling_rate; @@ -168,6 +169,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -188,6 +191,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -207,6 +212,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, }, /* @@ -226,6 +233,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, }, /* @@ -246,6 +255,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -265,6 +276,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -284,6 +297,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -303,6 +318,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = { 0x40, 16 }, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -323,6 +340,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -343,6 +362,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x24, 16 }, [SCLSR] = { 0x28, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -363,6 +384,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, }; @@ -781,7 +804,7 @@ static int sci_handle_errors(struct uart_port *port) struct sci_port *s = to_sci_port(port); /* Handle overruns */ - if (status & (1 << s->overrun_bit)) { + if (status & s->overrun_mask) { port->icount.overrun++; /* overrun error */ @@ -844,32 +867,17 @@ static int sci_handle_fifo_overrun(struct uart_port *port) struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg; - int copied = 0, offset; - u16 status, bit; - - switch (port->type) { - case PORT_SCIF: - case PORT_HSCIF: - offset = SCLSR; - break; - case PORT_SCIFA: - case PORT_SCIFB: - offset = SCxSR; - break; - default: - return 0; - } + int copied = 0; + u16 status; - reg = sci_getreg(port, offset); + reg = sci_getreg(port, s->overrun_reg); if (!reg->size) return 0; - status = serial_port_in(port, offset); - bit = 1 << s->overrun_bit; - - if (status & bit) { - status &= ~bit; - serial_port_out(port, offset, status); + status = serial_port_in(port, s->overrun_reg); + if (status & s->overrun_mask) { + status &= ~s->overrun_mask; + serial_port_out(port, s->overrun_reg, status); port->icount.overrun++; @@ -1021,15 +1029,11 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ssr_status = serial_port_in(port, SCxSR); scr_status = serial_port_in(port, SCSCR); - switch (port->type) { - case PORT_SCIF: - case PORT_HSCIF: - orer_status = serial_port_in(port, SCLSR); - break; - case PORT_SCIFA: - case PORT_SCIFB: + if (s->overrun_reg == SCxSR) orer_status = ssr_status; - break; + else { + if (sci_getreg(port, s->overrun_reg)->size) + orer_status = serial_port_in(port, s->overrun_reg); } err_enabled = scr_status & port_rx_irq_mask(port); @@ -1059,7 +1063,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ret = sci_br_interrupt(irq, ptr); /* Overrun Interrupt */ - if (orer_status & (1 << s->overrun_bit)) + if (orer_status & s->overrun_mask) sci_handle_fifo_overrun(port); return ret; @@ -2234,32 +2238,38 @@ static int sci_init_single(struct platform_device *dev, switch (p->type) { case PORT_SCIFB: port->fifosize = 256; - sci_port->overrun_bit = 9; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; sampling_rate = 16; break; case PORT_HSCIF: port->fifosize = 128; sampling_rate = 0; - sci_port->overrun_bit = 0; + sci_port->overrun_reg = SCLSR; + sci_port->overrun_mask = SCLSR_ORER; break; case PORT_SCIFA: port->fifosize = 64; - sci_port->overrun_bit = 9; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; sampling_rate = 16; break; case PORT_SCIF: port->fifosize = 16; if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { - sci_port->overrun_bit = 9; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; sampling_rate = 16; } else { - sci_port->overrun_bit = 0; + sci_port->overrun_reg = SCLSR; + sci_port->overrun_mask = SCLSR_ORER; sampling_rate = 32; } break; default: port->fifosize = 1; - sci_port->overrun_bit = 5; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCI_ORER; sampling_rate = 32; break; } @@ -2305,15 +2315,11 @@ static int sci_init_single(struct platform_device *dev, SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK; /* - * Establish sensible defaults for the overrun detection, unless - * the part has explicitly disabled support for it. - */ - - /* * Make the error mask inclusive of overrun detection, if * supported. */ - sci_port->error_mask |= 1 << sci_port->overrun_bit; + if (sci_port->overrun_reg == SCxSR) + sci_port->error_mask |= sci_port->overrun_mask; port->type = p->type; port->flags = UPF_FIXED_PORT | p->flags; diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index d5db81a0a430..3393f67b4e84 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -1,7 +1,115 @@ +#include <linux/bitops.h> #include <linux/serial_core.h> #include <linux/io.h> #include <linux/gpio.h> +#define SCI_MAJOR 204 +#define SCI_MINOR_START 8 + + +/* + * SCI register subset common for all port types. + * Not all registers will exist on all parts. + */ +enum { + SCSMR, /* Serial Mode Register */ + SCBRR, /* Bit Rate Register */ + SCSCR, /* Serial Control Register */ + SCxSR, /* Serial Status Register */ + SCFCR, /* FIFO Control Register */ + SCFDR, /* FIFO Data Count Register */ + SCxTDR, /* Transmit (FIFO) Data Register */ + SCxRDR, /* Receive (FIFO) Data Register */ + SCLSR, /* Line Status Register */ + SCTFDR, /* Transmit FIFO Data Count Register */ + SCRFDR, /* Receive FIFO Data Count Register */ + SCSPTR, /* Serial Port Register */ + HSSRR, /* Sampling Rate Register */ + SCPCR, /* Serial Port Control Register */ + SCPDR, /* Serial Port Data Register */ + + SCIx_NR_REGS, +}; + + +/* SCSMR (Serial Mode Register) */ +#define SCSMR_CHR BIT(6) /* 7-bit Character Length */ +#define SCSMR_PE BIT(5) /* Parity Enable */ +#define SCSMR_ODD BIT(4) /* Odd Parity */ +#define SCSMR_STOP BIT(3) /* Stop Bit Length */ +#define SCSMR_CKS 0x0003 /* Clock Select */ + +/* Serial Control Register, SCIFA/SCIFB only bits */ +#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */ +#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */ + +/* SCxSR (Serial Status Register) on SCI */ +#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */ +#define SCI_RDRF BIT(6) /* Receive Data Register Full */ +#define SCI_ORER BIT(5) /* Overrun Error */ +#define SCI_FER BIT(4) /* Framing Error */ +#define SCI_PER BIT(3) /* Parity Error */ +#define SCI_TEND BIT(2) /* Transmit End */ +#define SCI_RESERVED 0x03 /* All reserved bits */ + +#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER) + +#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF) +#define SCI_ERROR_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER) +#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE) +#define SCI_BREAK_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER) + +/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */ +#define SCIF_ER BIT(7) /* Receive Error */ +#define SCIF_TEND BIT(6) /* Transmission End */ +#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */ +#define SCIF_BRK BIT(4) /* Break Detect */ +#define SCIF_FER BIT(3) /* Framing Error */ +#define SCIF_PER BIT(2) /* Parity Error */ +#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */ +#define SCIF_DR BIT(0) /* Receive Data Ready */ +/* SCIF only (optional) */ +#define SCIF_PERC 0xf000 /* Number of Parity Errors */ +#define SCIF_FERC 0x0f00 /* Number of Framing Errors */ +/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */ +#define SCIFA_ORER BIT(9) /* Overrun Error */ + +#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER) + +#define SCIF_RDxF_CLEAR ~(SCIF_DR | SCIF_RDF) +#define SCIF_ERROR_CLEAR ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER) +#define SCIF_TDxE_CLEAR ~(SCIF_TDFE) +#define SCIF_BREAK_CLEAR ~(SCIF_PER | SCIF_FER | SCIF_BRK) + +/* SCFCR (FIFO Control Register) */ +#define SCFCR_MCE BIT(3) /* Modem Control Enable */ +#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */ +#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */ +#define SCFCR_LOOP BIT(0) /* Loopback Test */ + +/* SCLSR (Line Status Register) on (H)SCIF */ +#define SCLSR_ORER BIT(0) /* Overrun Error */ + +/* SCSPTR (Serial Port Register), optional */ +#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */ +#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */ +#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */ +#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */ +#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */ +#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */ + +/* HSSRR HSCIF */ +#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ + +/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ +#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */ +#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */ + +/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */ +#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */ +#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */ + + #define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) #define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) #define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) @@ -15,24 +123,24 @@ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7372) || \ defined(CONFIG_ARCH_R8A7740) -# define SCxSR_RDxF_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfffc) -# define SCxSR_ERROR_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfd73) -# define SCxSR_TDxE_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffdf) -# define SCxSR_BREAK_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffe3) +# define SCxSR_RDxF_CLEAR(port) \ + (serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR) +# define SCxSR_ERROR_CLEAR(port) \ + (serial_port_in(port, SCxSR) & SCIF_ERROR_CLEAR) +# define SCxSR_TDxE_CLEAR(port) \ + (serial_port_in(port, SCxSR) & SCIF_TDxE_CLEAR) +# define SCxSR_BREAK_CLEAR(port) \ + (serial_port_in(port, SCxSR) & SCIF_BREAK_CLEAR) #else -# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) -# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) -# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) -# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) +# define SCxSR_RDxF_CLEAR(port) \ + ((((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) & 0xff) +# define SCxSR_ERROR_CLEAR(port) \ + ((((port)->type == PORT_SCI) ? SCI_ERROR_CLEAR : SCIF_ERROR_CLEAR) & 0xff) +# define SCxSR_TDxE_CLEAR(port) \ + ((((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) & 0xff) +# define SCxSR_BREAK_CLEAR(port) \ + ((((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) & 0xff) #endif -/* SCFCR */ -#define SCFCR_RFRST 0x0002 -#define SCFCR_TFRST 0x0004 -#define SCFCR_MCE 0x0008 - -#define SCI_MAJOR 204 -#define SCI_MINOR_START 8 diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 9de3eabe5737..7214abe0d913 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -59,50 +59,7 @@ static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = { {9600, 1114979}, }; -static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = { - [0] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - }, - [1] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - }, - [2] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - }, - [3] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 3, - }, - }, - [4] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 4, - }, - }, - [5] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 5, - }, - }, -}; +static struct sirfsoc_uart_port *sirf_ports[SIRFSOC_UART_NR]; static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port) { @@ -116,8 +73,7 @@ static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port) struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status); - - return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0; + return (reg & ufifo_st->ff_empty(port)) ? TIOCSER_TEMT : 0; } static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port) @@ -290,8 +246,7 @@ 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, - SIRFSOC_UART_IO_TX_REASONABLE_CNT); + sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, @@ -417,7 +372,7 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) if (!tty) return -ENODEV; while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - ufifo_st->ff_empty(port->line))) { + ufifo_st->ff_empty(port))) { ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) | SIRFUART_DUMMY_READ; if (unlikely(uart_handle_sysrq_char(port, ch))) @@ -444,7 +399,7 @@ sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count) unsigned int num_tx = 0; while (!uart_circ_empty(xmit) && !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_full(port->line)) && + ufifo_st->ff_full(port)) && count--) { wr_regl(port, ureg->sirfsoc_tx_fifo_data, xmit->buf[xmit->tail]); @@ -669,8 +624,7 @@ recv_char: sirfsoc_uart_handle_rx_done(sirfport); } else { if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st)) - sirfsoc_uart_pio_rx_chars(port, - SIRFSOC_UART_IO_RX_MAX_CNT); + sirfsoc_uart_pio_rx_chars(port, port->fifosize); } spin_unlock(&port->lock); tty_flip_buffer_push(&state->port); @@ -684,10 +638,10 @@ recv_char: return IRQ_HANDLED; } else { sirfsoc_uart_pio_tx_chars(sirfport, - SIRFSOC_UART_IO_TX_REASONABLE_CNT); + port->fifosize); if ((uart_circ_empty(xmit)) && (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_empty(port->line))) + ufifo_st->ff_empty(port))) sirfsoc_uart_stop_tx(port); } } @@ -789,7 +743,7 @@ sirfsoc_usp_calc_sample_div(unsigned long set_rate, unsigned long ioclk_div = 0; unsigned long temp_delta; - for (sample_div = SIRF_MIN_SAMPLE_DIV; + for (sample_div = SIRF_USP_MIN_SAMPLE_DIV; sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) { temp_delta = ioclk_rate - (ioclk_rate + (set_rate * sample_div) / 2) @@ -1032,19 +986,10 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); - if (!state) { - if (sirfport->is_bt_uart) { - clk_prepare_enable(sirfport->clk_noc); - clk_prepare_enable(sirfport->clk_general); - } + if (!state) clk_prepare_enable(sirfport->clk); - } else { + else clk_disable_unprepare(sirfport->clk); - if (sirfport->is_bt_uart) { - clk_disable_unprepare(sirfport->clk_general); - clk_disable_unprepare(sirfport->clk_noc); - } - } } static int sirfsoc_uart_startup(struct uart_port *port) @@ -1064,7 +1009,6 @@ static int sirfsoc_uart_startup(struct uart_port *port) index, port->irq); goto irq_err; } - /* initial hardware settings */ wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) | @@ -1196,27 +1140,29 @@ sirfsoc_uart_console_setup(struct console *co, char *options) unsigned int bits = 8; unsigned int parity = 'n'; unsigned int flow = 'n'; - struct uart_port *port = &sirfsoc_uart_ports[co->index].port; - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct sirfsoc_uart_port *sirfport; + struct sirfsoc_register *ureg; if (co->index < 0 || co->index >= SIRFSOC_UART_NR) return -EINVAL; - - if (!port->mapbase) + sirfport = sirf_ports[co->index]; + if (!sirfport) + return -ENODEV; + ureg = &sirfport->uart_reg->uart_reg; + if (!sirfport->port.mapbase) return -ENODEV; /* enable usp in mode1 register */ if (sirfport->uart_reg->uart_type == SIRF_USP_UART) - wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN | + wr_regl(&sirfport->port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN | SIRFSOC_USP_ENDIAN_CTRL_LSBF); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - port->cons = co; + sirfport->port.cons = co; /* default console tx/rx transfer using io mode */ sirfport->rx_dma_chan = NULL; sirfport->tx_dma_chan = NULL; - return uart_set_options(port, co, baud, parity, bits, flow); + return uart_set_options(&sirfport->port, co, baud, parity, bits, flow); } static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) @@ -1224,8 +1170,8 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; - while (rd_regl(port, - ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line)) + while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & + ufifo_st->ff_full(port)) cpu_relax(); wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch); } @@ -1233,8 +1179,10 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) static void sirfsoc_uart_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &sirfsoc_uart_ports[co->index].port; - uart_console_write(port, s, count, sirfsoc_uart_console_putchar); + struct sirfsoc_uart_port *sirfport = sirf_ports[co->index]; + + uart_console_write(&sirfport->port, s, count, + sirfsoc_uart_console_putchar); } static struct console sirfsoc_uart_console = { @@ -1293,16 +1241,15 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) const struct of_device_id *match; match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node); - if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) { - dev_err(&pdev->dev, - "Unable to find cell-index in uart node.\n"); - ret = -EFAULT; + sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL); + if (!sirfport) { + ret = -ENOMEM; goto err; } - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) - pdev->id += ((struct sirfsoc_uart_register *) - match->data)->uart_param.register_uart_nr; - sirfport = &sirfsoc_uart_ports[pdev->id]; + sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial"); + sirf_ports[sirfport->port.line] = sirfport; + sirfport->port.iotype = UPIO_MEM; + sirfport->port.flags = UPF_BOOT_AUTOCONF; port = &sirfport->port; port->dev = &pdev->dev; port->private_data = sirfport; @@ -1393,20 +1340,6 @@ usp_no_flow_control: goto err; } port->uartclk = clk_get_rate(sirfport->clk); - if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) { - sirfport->clk_general = devm_clk_get(&pdev->dev, "general"); - if (IS_ERR(sirfport->clk_general)) { - ret = PTR_ERR(sirfport->clk_general); - goto err; - } - sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc"); - if (IS_ERR(sirfport->clk_noc)) { - ret = PTR_ERR(sirfport->clk_noc); - goto err; - } - sirfport->is_bt_uart = true; - } else - sirfport->is_bt_uart = false; port->ops = &sirfsoc_uart_ops; spin_lock_init(&port->lock); diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index 727eb6b88fff..af2f1878330a 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -6,11 +6,10 @@ * Licensed under GPLv2 or later. */ #include <linux/bitops.h> +#include <linux/log2.h> struct sirfsoc_uart_param { const char *uart_name; const char *port_name; - u32 uart_nr; - u32 register_uart_nr; }; struct sirfsoc_register { @@ -45,8 +44,8 @@ struct sirfsoc_register { u32 sirfsoc_async_param_reg; }; -typedef u32 (*fifo_full_mask)(int line); -typedef u32 (*fifo_empty_mask)(int line); +typedef u32 (*fifo_full_mask)(struct uart_port *port); +typedef u32 (*fifo_empty_mask)(struct uart_port *port); struct sirfsoc_fifo_status { fifo_full_mask ff_full; @@ -105,21 +104,20 @@ struct sirfsoc_uart_register { enum sirfsoc_uart_type uart_type; }; -u32 usp_ff_full(int line) +u32 uart_usp_ff_full_mask(struct uart_port *port) { - return 0x80; -} -u32 usp_ff_empty(int line) -{ - return 0x100; -} -u32 uart_ff_full(int line) -{ - return (line == 1) ? (0x20) : (0x80); + u32 full_bit; + + full_bit = ilog2(port->fifosize); + return (1 << full_bit); } -u32 uart_ff_empty(int line) + +u32 uart_usp_ff_empty_mask(struct uart_port *port) { - return (line == 1) ? (0x40) : (0x100); + u32 empty_bit; + + empty_bit = ilog2(port->fifosize); + return (1 << empty_bit); } struct sirfsoc_uart_register sirfsoc_usp = { .uart_reg = { @@ -177,14 +175,12 @@ struct sirfsoc_uart_register sirfsoc_usp = { .sirfsoc_rxd_brk = BIT(15), }, .fifo_status = { - .ff_full = usp_ff_full, - .ff_empty = usp_ff_empty, + .ff_full = uart_usp_ff_full_mask, + .ff_empty = uart_usp_ff_empty_mask, }, .uart_param = { .uart_name = "ttySiRF", .port_name = "sirfsoc-uart", - .uart_nr = 2, - .register_uart_nr = 3, }, }; @@ -249,14 +245,12 @@ struct sirfsoc_uart_register sirfsoc_uart = { .sirfsoc_rts = BIT(15), }, .fifo_status = { - .ff_full = uart_ff_full, - .ff_empty = uart_ff_empty, + .ff_full = uart_usp_ff_full_mask, + .ff_empty = uart_usp_ff_empty_mask, }, .uart_param = { .uart_name = "ttySiRF", .port_name = "sirfsoc_uart", - .uart_nr = 3, - .register_uart_nr = 0, }, }; /* uart io ctrl */ @@ -300,6 +294,7 @@ struct sirfsoc_uart_register sirfsoc_uart = { /* Macro Specific*/ #define SIRFUART_INT_EN_CLR 0x0060 /* Baud Rate Calculation */ +#define SIRF_USP_MIN_SAMPLE_DIV 0x1 #define SIRF_MIN_SAMPLE_DIV 0xf #define SIRF_MAX_SAMPLE_DIV 0x3f #define SIRF_IOCLK_DIV_MAX 0xffff @@ -334,7 +329,7 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFUART_RECV_TIMEOUT(port, x) \ (((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16) -#define SIRFUART_FIFO_THD(port) ((port->line) == 1 ? 16 : 64) +#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1) #define SIRFUART_ERR_INT_STAT(port, unit_st) \ (uint_st->sirfsoc_rx_oflow | \ uint_st->sirfsoc_frm_err | \ @@ -365,16 +360,12 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFSOC_UART_MINOR 0 #define SIRFUART_PORT_NAME "sirfsoc-uart" #define SIRFUART_MAP_SIZE 0x200 -#define SIRFSOC_UART_NR 6 +#define SIRFSOC_UART_NR 11 #define SIRFSOC_PORT_TYPE 0xa5 /* Uart Common Use Macro*/ #define SIRFSOC_RX_DMA_BUF_SIZE 256 #define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3) -#define LOOP_DMA_BUFA_FILL 1 -#define LOOP_DMA_BUFB_FILL 2 -#define TX_TRAN_PIO 1 -#define TX_TRAN_DMA 2 /* Uart Fifo Level Chk */ #define SIRFUART_TX_FIFO_SC_OFFSET 0 #define SIRFUART_TX_FIFO_LC_OFFSET 10 @@ -417,10 +408,6 @@ struct sirfsoc_uart_port { struct uart_port port; struct clk *clk; - /* UART6 for BT usage in A7DA platform need multi-clock source */ - bool is_bt_uart; - struct clk *clk_general; - struct clk *clk_noc; /* for SiRFatlas7, there are SET/CLR for UART_INT_EN */ bool is_atlas7; struct sirfsoc_uart_register *uart_reg; @@ -447,10 +434,6 @@ struct sirfsoc_uart_port { #define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) /* UART Port Mask */ -#define SIRFUART_FIFOLEVEL_MASK(port) ((port->line == 1) ? (0x1f) : (0x7f)) -#define SIRFUART_FIFOFULL_MASK(port) ((port->line == 1) ? (0x20) : (0x80)) -#define SIRFUART_FIFOEMPTY_MASK(port) ((port->line == 1) ? (0x40) : (0x100)) - -/* I/O Mode */ -#define SIRFSOC_UART_IO_RX_MAX_CNT 256 -#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 256 +#define SIRFUART_FIFOLEVEL_MASK(port) ((port->fifosize - 1) & 0xFFF) +#define SIRFUART_FIFOFULL_MASK(port) (port->fifosize & 0xFFF) +#define SIRFUART_FIFOEMPTY_MASK(port) ((port->fifosize & 0xFFF) << 1) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 3ddbac767db3..009e0dbc12d2 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1075,7 +1075,8 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch) writel(ch, port->membase + CDNS_UART_FIFO_OFFSET); } -static void cdns_early_write(struct console *con, const char *s, unsigned n) +static void __init cdns_early_write(struct console *con, const char *s, + unsigned n) { struct earlycon_device *dev = con->data; diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index b7991707ffc0..2fac7123b274 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -4410,7 +4410,8 @@ static void synclink_cleanup(void) printk("Unloading %s: %s\n", driver_name, driver_version); if (serial_driver) { - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); put_tty_driver(serial_driver); @@ -7751,7 +7752,8 @@ static int hdlcdev_open(struct net_device *dev) printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -8018,7 +8020,8 @@ static int hdlcdev_init(struct mgsl_struct *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); return -ENOMEM; } @@ -8039,7 +8042,8 @@ static int hdlcdev_init(struct mgsl_struct *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -8075,7 +8079,8 @@ static int synclink_init_one (struct pci_dev *dev, return -EIO; } - if (!(info = mgsl_allocate_device())) { + info = mgsl_allocate_device(); + if (!info) { printk("can't allocate device instance data.\n"); return -EIO; } diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 0e8c39b6ccd4..0ea8eee00178 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1539,7 +1539,8 @@ static int hdlcdev_open(struct net_device *dev) DBGINFO(("%s hdlcdev_open\n", dev->name)); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -1803,7 +1804,8 @@ static int hdlcdev_init(struct slgt_info *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name); return -ENOMEM; } @@ -1824,7 +1826,8 @@ static int hdlcdev_init(struct slgt_info *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -1879,7 +1882,8 @@ static void rx_async(struct slgt_info *info) stat = 0; - if ((status = *(p+1) & (BIT1 + BIT0))) { + status = *(p + 1) & (BIT1 + BIT0); + if (status) { if (status & BIT1) icount->parity++; else if (status & BIT0) @@ -3755,7 +3759,8 @@ static void slgt_cleanup(void) if (serial_driver) { for (info=slgt_device_list ; info != NULL ; info=info->next_device) tty_unregister_device(serial_driver, info->line); - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) DBGERR(("tty_unregister_driver error=%d\n", rc)); put_tty_driver(serial_driver); } diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index c3f90910fed9..08633a8139ff 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1655,7 +1655,8 @@ static int hdlcdev_open(struct net_device *dev) printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -1922,7 +1923,8 @@ static int hdlcdev_init(SLMP_INFO *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); return -ENOMEM; } @@ -1943,7 +1945,8 @@ static int hdlcdev_init(SLMP_INFO *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -3920,7 +3923,8 @@ static void synclinkmp_cleanup(void) printk("Unloading %s %s\n", driver_name, driver_version); if (serial_driver) { - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); put_tty_driver(serial_driver); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 2f78b77f0f81..4cf263d7dffc 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -286,7 +286,8 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size, change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL); if (change || left < size) { /* This is the slow path - looking for new buffers to use */ - if ((n = tty_buffer_alloc(port, size)) != NULL) { + n = tty_buffer_alloc(port, size); + if (n != NULL) { n->flags = flags; buf->tail = n; b->commit = b->used; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index e5695467598f..57fc6ee12332 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -235,7 +235,6 @@ static void tty_del_file(struct file *file) /** * tty_name - return tty naming * @tty: tty structure - * @buf: buffer for output * * Convert a tty structure into a name. The name reflects the kernel * naming policy and if udev is in use may not reflect user space @@ -243,13 +242,11 @@ static void tty_del_file(struct file *file) * Locking: none */ -char *tty_name(struct tty_struct *tty, char *buf) +const char *tty_name(const struct tty_struct *tty) { if (!tty) /* Hmm. NULL pointer. That's fun. */ - strcpy(buf, "NULL tty"); - else - strcpy(buf, tty->name); - return buf; + return "NULL tty"; + return tty->name; } EXPORT_SYMBOL(tty_name); @@ -770,8 +767,7 @@ static void do_tty_hangup(struct work_struct *work) void tty_hangup(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - char buf[64]; - printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s hangup...\n", tty_name(tty)); #endif schedule_work(&tty->hangup_work); } @@ -790,9 +786,7 @@ EXPORT_SYMBOL(tty_hangup); void tty_vhangup(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - char buf[64]; - - printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty)); #endif __tty_hangup(tty, 0); } @@ -831,9 +825,7 @@ void tty_vhangup_self(void) static void tty_vhangup_session(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - char buf[64]; - - printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty)); #endif __tty_hangup(tty, 1); } @@ -1769,7 +1761,6 @@ int tty_release(struct inode *inode, struct file *filp) struct tty_struct *o_tty = NULL; int do_sleep, final; int idx; - char buf[64]; long timeout = 0; int once = 1; @@ -1793,7 +1784,7 @@ int tty_release(struct inode *inode, struct file *filp) #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__, - tty_name(tty, buf), tty->count); + tty_name(tty), tty->count); #endif if (tty->ops->close) @@ -1844,7 +1835,7 @@ int tty_release(struct inode *inode, struct file *filp) if (once) { once = 0; printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", - __func__, tty_name(tty, buf)); + __func__, tty_name(tty)); } schedule_timeout_killable(timeout); if (timeout < 120 * HZ) @@ -1856,13 +1847,13 @@ int tty_release(struct inode *inode, struct file *filp) if (o_tty) { if (--o_tty->count < 0) { printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n", - __func__, o_tty->count, tty_name(o_tty, buf)); + __func__, o_tty->count, tty_name(o_tty)); o_tty->count = 0; } } if (--tty->count < 0) { printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n", - __func__, tty->count, tty_name(tty, buf)); + __func__, tty->count, tty_name(tty)); tty->count = 0; } @@ -1905,7 +1896,7 @@ int tty_release(struct inode *inode, struct file *filp) return 0; #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf)); + printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty)); #endif /* * Ask the line discipline code to release its structures @@ -1916,7 +1907,8 @@ int tty_release(struct inode *inode, struct file *filp) tty_flush_works(tty); #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf)); + printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, + tty_name(tty)); #endif /* * The release_tty function takes care of the details of clearing diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 8e53fe469664..5232fb60b0b1 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -211,9 +211,7 @@ int tty_unthrottle_safe(struct tty_struct *tty) void tty_wait_until_sent(struct tty_struct *tty, long timeout) { #ifdef TTY_DEBUG_WAIT_UNTIL_SENT - char buf[64]; - - printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty)); #endif if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 3737f55272d2..c07fb5d9bcf9 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -22,9 +22,8 @@ #undef LDISC_DEBUG_HANGUP #ifdef LDISC_DEBUG_HANGUP -#define tty_ldisc_debug(tty, f, args...) ({ \ - char __b[64]; \ - printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \ +#define tty_ldisc_debug(tty, f, args...) ({ \ + printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty), ##args); \ }) #else #define tty_ldisc_debug(tty, f, args...) @@ -483,7 +482,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) { - char buf[64]; struct tty_ldisc *new_ldisc; int r; @@ -504,7 +502,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) if (r < 0) panic("Couldn't open N_TTY ldisc for " "%s --- error %d.", - tty_name(tty, buf), r); + tty_name(tty), r); } } diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c index 0ffb0cbe2823..ad7eba5ca380 100644 --- a/drivers/tty/tty_ldsem.c +++ b/drivers/tty/tty_ldsem.c @@ -299,7 +299,8 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout) timeout = schedule_timeout(timeout); raw_spin_lock_irq(&sem->wait_lock); set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((locked = writer_trylock(sem))) + locked = writer_trylock(sem); + if (locked) break; } diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 59b25e039968..c8c91f0476a2 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -261,19 +261,22 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode) int m; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; - else if (!(p = *conp->vc_uni_pagedir_loc)) - return glyph; - else if (use_unicode) { - if (!p->inverse_trans_unicode) + else { + p = *conp->vc_uni_pagedir_loc; + if (!p) return glyph; - else - return p->inverse_trans_unicode[glyph]; - } else { - m = inv_translate[conp->vc_num]; - if (!p->inverse_translations[m]) - return glyph; - else - return p->inverse_translations[m][glyph]; + else if (use_unicode) { + if (!p->inverse_trans_unicode) + return glyph; + else + return p->inverse_trans_unicode[glyph]; + } else { + m = inv_translate[conp->vc_num]; + if (!p->inverse_translations[m]) + return glyph; + else + return p->inverse_translations[m][glyph]; + } } } EXPORT_SYMBOL_GPL(inverse_translate); @@ -397,7 +400,8 @@ static void con_release_unimap(struct uni_pagedir *p) if (p == dflt) dflt = NULL; for (i = 0; i < 32; i++) { - if ((p1 = p->uni_pgdir[i]) != NULL) { + p1 = p->uni_pgdir[i]; + if (p1 != NULL) { for (j = 0; j < 32; j++) kfree(p1[j]); kfree(p1); @@ -473,14 +477,16 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) int i, n; u16 **p1, *p2; - if (!(p1 = p->uni_pgdir[n = unicode >> 11])) { + p1 = p->uni_pgdir[n = unicode >> 11]; + if (!p1) { p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL); if (!p1) return -ENOMEM; for (i = 0; i < 32; i++) p1[i] = NULL; } - if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) { + p2 = p1[n = (unicode >> 6) & 0x1f]; + if (!p2) { p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL); if (!p2) return -ENOMEM; memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ @@ -569,10 +575,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) * entries from "p" (old) to "q" (new). */ l = 0; /* unicode value */ - for (i = 0; i < 32; i++) - if ((p1 = p->uni_pgdir[i])) - for (j = 0; j < 32; j++) - if ((p2 = p1[j])) { + for (i = 0; i < 32; i++) { + p1 = p->uni_pgdir[i]; + if (p1) + for (j = 0; j < 32; j++) { + p2 = p1[j]; + if (p2) { for (k = 0; k < 64; k++, l++) if (p2[k] != 0xffff) { /* @@ -593,9 +601,11 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* Account for row of 64 empty entries */ l += 64; } + } else /* Account for empty table */ l += 32 * 64; + } /* * Finished copying font table, set vc_uni_pagedir to new table @@ -735,10 +745,12 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni ect = 0; if (*vc->vc_uni_pagedir_loc) { p = *vc->vc_uni_pagedir_loc; - for (i = 0; i < 32; i++) - if ((p1 = p->uni_pgdir[i])) - for (j = 0; j < 32; j++) - if ((p2 = *(p1++))) + for (i = 0; i < 32; i++) { + p1 = p->uni_pgdir[i]; + if (p1) + for (j = 0; j < 32; j++) { + p2 = *(p1++); + if (p2) for (k = 0; k < 64; k++) { if (*p2 < MAX_GLYPH && ect++ < ct) { __put_user((u_short)((i<<11)+(j<<6)+k), @@ -749,6 +761,8 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni } p2++; } + } + } } __put_user(ect, uct); console_unlock(); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 4a24eb2b0ede..8fe52989b380 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -108,6 +108,7 @@ #define CON_DRIVER_FLAG_MODULE 1 #define CON_DRIVER_FLAG_INIT 2 #define CON_DRIVER_FLAG_ATTR 4 +#define CON_DRIVER_FLAG_ZOMBIE 8 struct con_driver { const struct consw *con; @@ -135,6 +136,7 @@ const struct consw *conswitchp; */ #define DEFAULT_BELL_PITCH 750 #define DEFAULT_BELL_DURATION (HZ/8) +#define DEFAULT_CURSOR_BLINK_MS 200 struct vc vc_cons [MAX_NR_CONSOLES]; @@ -153,6 +155,7 @@ static int set_vesa_blanking(char __user *p); static void set_cursor(struct vc_data *vc); static void hide_cursor(struct vc_data *vc); static void console_callback(struct work_struct *ignored); +static void con_driver_unregister_callback(struct work_struct *ignored); static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); @@ -182,6 +185,7 @@ static int blankinterval = 10*60; core_param(consoleblank, blankinterval, int, 0444); static DECLARE_WORK(console_work, console_callback); +static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback); /* * fg_console is the current virtual console, @@ -1590,6 +1594,13 @@ static void setterm_command(struct vc_data *vc) case 15: /* activate the previous console */ set_console(last_console); break; + case 16: /* set cursor blink duration in msec */ + if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 && + vc->vc_par[1] <= USHRT_MAX) + vc->vc_cur_blink_ms = vc->vc_par[1]; + else + vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS; + break; } } @@ -1717,6 +1728,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_bell_pitch = DEFAULT_BELL_PITCH; vc->vc_bell_duration = DEFAULT_BELL_DURATION; + vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS; gotoxy(vc, 0, 0); save_cur(vc); @@ -3192,22 +3204,6 @@ err: #ifdef CONFIG_VT_HW_CONSOLE_BINDING -static int con_is_graphics(const struct consw *csw, int first, int last) -{ - int i, retval = 0; - - for (i = first; i <= last; i++) { - struct vc_data *vc = vc_cons[i].d; - - if (vc && vc->vc_mode == KD_GRAPHICS) { - retval = 1; - break; - } - } - - return retval; -} - /* unlocked version of unbind_con_driver() */ int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt) { @@ -3293,8 +3289,7 @@ static int vt_bind(struct con_driver *con) const struct consw *defcsw = NULL, *csw = NULL; int i, more = 1, first = -1, last = -1, deflt = 0; - if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || - con_is_graphics(con->con, con->first, con->last)) + if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE)) goto err; csw = con->con; @@ -3345,8 +3340,7 @@ static int vt_unbind(struct con_driver *con) int i, more = 1, first = -1, last = -1, deflt = 0; int ret; - if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || - con_is_graphics(con->con, con->first, con->last)) + if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE)) goto err; csw = con->con; @@ -3596,7 +3590,8 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) for (i = 0; i < MAX_NR_CON_DRIVER; i++) { con_driver = ®istered_con_driver[i]; - if (con_driver->con == NULL) { + if (con_driver->con == NULL && + !(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) { con_driver->con = csw; con_driver->desc = desc; con_driver->node = i; @@ -3658,16 +3653,20 @@ int do_unregister_con_driver(const struct consw *csw) struct con_driver *con_driver = ®istered_con_driver[i]; if (con_driver->con == csw) { - vtconsole_deinit_device(con_driver); - device_destroy(vtconsole_class, - MKDEV(0, con_driver->node)); + /* + * Defer the removal of the sysfs entries since that + * will acquire the kernfs s_active lock and we can't + * acquire this lock while holding the console lock: + * the unbind sysfs entry imposes already the opposite + * order. Reset con already here to prevent any later + * lookup to succeed and mark this slot as zombie, so + * it won't get reused until we complete the removal + * in the deferred work. + */ con_driver->con = NULL; - con_driver->desc = NULL; - con_driver->dev = NULL; - con_driver->node = 0; - con_driver->flag = 0; - con_driver->first = 0; - con_driver->last = 0; + con_driver->flag = CON_DRIVER_FLAG_ZOMBIE; + schedule_work(&con_driver_unregister_work); + return 0; } } @@ -3676,6 +3675,39 @@ int do_unregister_con_driver(const struct consw *csw) } EXPORT_SYMBOL_GPL(do_unregister_con_driver); +static void con_driver_unregister_callback(struct work_struct *ignored) +{ + int i; + + console_lock(); + + for (i = 0; i < MAX_NR_CON_DRIVER; i++) { + struct con_driver *con_driver = ®istered_con_driver[i]; + + if (!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) + continue; + + console_unlock(); + + vtconsole_deinit_device(con_driver); + device_destroy(vtconsole_class, MKDEV(0, con_driver->node)); + + console_lock(); + + if (WARN_ON_ONCE(con_driver->con)) + con_driver->con = NULL; + con_driver->desc = NULL; + con_driver->dev = NULL; + con_driver->node = 0; + WARN_ON_ONCE(con_driver->flag != CON_DRIVER_FLAG_ZOMBIE); + con_driver->flag = 0; + con_driver->first = 0; + con_driver->last = 0; + } + + console_unlock(); +} + /* * If we support more console drivers, this function is used * when a driver wants to take over some existing consoles |