From 6f210c18c1c0f016772c8cd51ae12a02bfb9e7ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Wed, 27 Apr 2016 11:58:32 +0200 Subject: serial: 8250_pci: fix divide error bug if baud rate is 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 21947ba654a6 ("serial: 8250_pci: replace switch-case by formula"), the 8250 driver crashes in the byt_set_termios() function with a divide error. This is caused by the fact that a baud rate of 0 (B0) is not handled properly. Fix it by falling back to B9600 in this case. Signed-off-by: David Müller Fixes: 21947ba654a6 ("serial: 8250_pci: replace switch-case by formula") Cc: stable@vger.kernel.org Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 98862aa..4eedd1d 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1377,6 +1377,9 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, unsigned long m, n; u32 reg; + /* Gracefully handle the B0 case: fall back to B9600 */ + fuart = fuart ? fuart : 9600 * 16; + /* Get Fuart closer to Fref */ fuart *= rounddown_pow_of_two(fref / fuart); -- cgit v1.1 From d175feca89a1c162f60f4e3560ca7bc9437c65eb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 22 Mar 2016 18:09:51 +0100 Subject: TTY: n_gsm, fix false positive WARN_ON Dmitry reported, that the current cleanup code in n_gsm can trigger a warning: WARNING: CPU: 2 PID: 24238 at drivers/tty/n_gsm.c:2048 gsm_cleanup_mux+0x166/0x6b0() ... Call Trace: ... [] warn_slowpath_null+0x29/0x30 kernel/panic.c:490 [] gsm_cleanup_mux+0x166/0x6b0 drivers/tty/n_gsm.c:2048 [] gsmld_open+0x5b7/0x7a0 drivers/tty/n_gsm.c:2386 [] tty_ldisc_open.isra.2+0x78/0xd0 drivers/tty/tty_ldisc.c:447 [] tty_set_ldisc+0x1ca/0xa70 drivers/tty/tty_ldisc.c:567 [< inline >] tiocsetd drivers/tty/tty_io.c:2650 [] tty_ioctl+0xb2a/0x2140 drivers/tty/tty_io.c:2883 ... But this is a legal path when open fails to find a space in the gsm_mux array and tries to clean up. So make it a standard test instead of a warning. Reported-by: "Dmitry Vyukov" Cc: Alan Cox Link: http://lkml.kernel.org/r/CACT4Y+bHQbAB68VFi7Romcs-Z9ZW3kQRvcq+BvHH1oa5NcAdLA@mail.gmail.com Fixes: 5a640967 ("tty/n_gsm.c: fix a memory leak in gsmld_open()") Cc: stable Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c016207..365dfd8 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2045,7 +2045,9 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm) } } spin_unlock(&gsm_mux_lock); - WARN_ON(i == MAX_MUX); + /* open failed before registering => nothing to do */ + if (i == MAX_MUX) + return; /* In theory disconnecting DLCI 0 is sufficient but for some modems this is apparently not the case. */ -- cgit v1.1 From 5be605ac9af979265d7b64c160ad9928088a78be Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 12 Apr 2016 14:51:40 +0200 Subject: tty/serial: atmel: fix hardware handshake selection Commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled") actually allowed to enable hardware handshaking. Before, the CRTSCTS flags was silently ignored. As the DMA controller can't drive RTS (as explain in the commit message). Ensure that hardware flow control stays disabled when DMA is used and FIFOs are not available. Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Fixes: 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled") Cc: stable # v4.0+ Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d9439e6..954941d 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -274,6 +274,13 @@ static bool atmel_use_dma_rx(struct uart_port *port) return atmel_port->use_dma_rx; } +static bool atmel_use_fifo(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->fifo_size; +} + static unsigned int atmel_get_lines_status(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -2090,7 +2097,12 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, mode |= ATMEL_US_USMODE_RS485; } else if (termios->c_cflag & CRTSCTS) { /* RS232 with hardware handshake (RTS/CTS) */ - mode |= ATMEL_US_USMODE_HWHS; + if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) { + dev_info(port->dev, "not enabling hardware flow control because DMA is used"); + termios->c_cflag &= ~CRTSCTS; + } else { + mode |= ATMEL_US_USMODE_HWHS; + } } else { /* RS232 without hadware handshake */ mode |= ATMEL_US_USMODE_NORMAL; -- cgit v1.1 From 1aabf523a288b09d660992c22e307110c70f746d Mon Sep 17 00:00:00 2001 From: Christopher Covington Date: Fri, 1 Apr 2016 17:23:58 -0400 Subject: tty: amba-pl011: Use 32-bit accesses for SBSA UART Version 2 of the Server Base System Architecture (SBSAv2) describes UART hardware registers as 32 bits wide, giving no guidance on access sizes. The SBSA UART driver previously assumed partial-length 16 and 8 bit accesses would work. But the SBSAv2 UART hardware on the Qualcomm Technologies QDF2432 only supports full-length 32 bit register accesses, so use those exclusively. This is compatible with SBSAv3, which explicitly requires UART hardware support 32 (and 16 and sometimes 8) bit accesses. Tested on Juno, Midway, QDF2432, Seattle, and X-Gene 1. Tested-by: Mark Langsdorf Tested-by: Andre Przywara Acked-by: Andre Przywara Signed-off-by: Christopher Covington Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 7c198e0..a2aa655 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -121,6 +121,7 @@ static struct vendor_data vendor_arm = { static struct vendor_data vendor_sbsa = { .reg_offset = pl011_std_offsets, + .access_32b = true, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, -- cgit v1.1 From 18900ca65a8553edc608b6c9d518eb31e6c09ba1 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:06:48 -0700 Subject: tty: Replace TTY_IO_ERROR bit tests with tty_io_error() Abstract TTY_IO_ERROR status test treewide with tty_io_error(). NB: tty->flags uses atomic bit ops; replace non-atomic bit test with test_bit(). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- arch/ia64/hp/sim/simserial.c | 2 +- drivers/char/pcmcia/synclink_cs.c | 2 +- drivers/isdn/i4l/isdn_tty.c | 6 +++--- drivers/s390/char/tty3270.c | 4 ++-- drivers/staging/dgnc/dgnc_tty.c | 2 +- drivers/tty/amiserial.c | 6 +++--- drivers/tty/mxser.c | 7 +++---- drivers/tty/pty.c | 2 +- drivers/tty/serial/crisv10.c | 5 ++--- drivers/tty/serial/serial_core.c | 8 ++++---- drivers/tty/synclink.c | 4 ++-- drivers/tty/synclink_gt.c | 4 ++-- drivers/tty/synclinkmp.c | 4 ++-- drivers/tty/tty_io.c | 5 ++--- drivers/tty/tty_port.c | 2 +- include/linux/tty.h | 5 +++++ net/irda/ircomm/ircomm_tty.c | 2 +- net/irda/ircomm/ircomm_tty_ioctl.c | 6 +++--- 18 files changed, 39 insertions(+), 37 deletions(-) diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index e70cade..21fd50d 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -300,7 +300,7 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && (cmd != TIOCMIWAIT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 22c2765..825db42 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2246,7 +2246,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCMIWAIT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; } diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 947d5c9..f1edc08 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1351,7 +1351,7 @@ isdn_tty_tiocmget(struct tty_struct *tty) if (isdn_tty_paranoia_check(info, tty->name, __func__)) return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; mutex_lock(&modem_info_mutex); @@ -1378,7 +1378,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, if (isdn_tty_paranoia_check(info, tty->name, __func__)) return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; #ifdef ISDN_DEBUG_MODEM_IOCTL @@ -1419,7 +1419,7 @@ isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg) if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl")) return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index e96fc7f..080a987 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1804,7 +1804,7 @@ static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd, tp = tty->driver_data; if (!tp) return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; return kbd_ioctl(tp->kbd, cmd, arg); } @@ -1818,7 +1818,7 @@ static long tty3270_compat_ioctl(struct tty_struct *tty, tp = tty->driver_data; if (!tp) return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg)); } diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index bcd2bdf..5c22159 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -1255,7 +1255,7 @@ static int dgnc_block_til_ready(struct tty_struct *tty, if (file->f_flags & O_NONBLOCK) break; - if (tty->flags & (1 << TTY_IO_ERROR)) { + if (tty_io_error(tty)) { retval = -EIO; break; } diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index eacf4c9..183e98e 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1143,7 +1143,7 @@ static int rs_tiocmget(struct tty_struct *tty) if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; control = info->MCR; @@ -1165,7 +1165,7 @@ static int rs_tiocmset(struct tty_struct *tty, unsigned int set, if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; local_irq_save(flags); @@ -1250,7 +1250,7 @@ static int rs_ioctl(struct tty_struct *tty, if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 2f12bb9..f23c2a1 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1334,7 +1334,7 @@ static int mxser_tiocmget(struct tty_struct *tty) if (tty->index == MXSER_PORTS) return -ENOIOCTLCMD; - if (test_bit(TTY_IO_ERROR, &tty->flags)) + if (tty_io_error(tty)) return -EIO; control = info->MCR; @@ -1361,7 +1361,7 @@ static int mxser_tiocmset(struct tty_struct *tty, if (tty->index == MXSER_PORTS) return -ENOIOCTLCMD; - if (test_bit(TTY_IO_ERROR, &tty->flags)) + if (tty_io_error(tty)) return -EIO; spin_lock_irqsave(&info->slock, flags); @@ -1715,8 +1715,7 @@ static int mxser_ioctl(struct tty_struct *tty, return 0; } - if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && - test_bit(TTY_IO_ERROR, &tty->flags)) + if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && tty_io_error(tty)) return -EIO; switch (cmd) { diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 0058d9fb..a8a292f 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -44,7 +44,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) if (tty->driver->subtype == PTY_TYPE_MASTER) WARN_ON(tty->count > 1); else { - if (test_bit(TTY_IO_ERROR, &tty->flags)) + if (tty_io_error(tty)) return; if (tty->count > 2) return; diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index c0172bf54..5469903 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -3445,7 +3445,7 @@ rs_ioctl(struct tty_struct *tty, if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; } @@ -3755,8 +3755,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { + if ((filp->f_flags & O_NONBLOCK) || tty_io_error(tty)) { info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a126a60..67b3950 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -969,7 +969,7 @@ static int uart_tiocmget(struct tty_struct *tty) int result = -EIO; mutex_lock(&port->mutex); - if (!(tty->flags & (1 << TTY_IO_ERROR))) { + if (!tty_io_error(tty)) { result = uport->mctrl; spin_lock_irq(&uport->lock); result |= uport->ops->get_mctrl(uport); @@ -989,7 +989,7 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) int ret = -EIO; mutex_lock(&port->mutex); - if (!(tty->flags & (1 << TTY_IO_ERROR))) { + if (!tty_io_error(tty)) { uart_update_mctrl(uport, set, clear); ret = 0; } @@ -1238,7 +1238,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, if (ret != -ENOIOCTLCMD) goto out; - if (tty->flags & (1 << TTY_IO_ERROR)) { + if (tty_io_error(tty)) { ret = -EIO; goto out; } @@ -1257,7 +1257,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, mutex_lock(&port->mutex); - if (tty->flags & (1 << TTY_IO_ERROR)) { + if (tty_io_error(tty)) { ret = -EIO; goto out_up; } diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index f5476e2..8b22772 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -2972,7 +2972,7 @@ static int mgsl_ioctl(struct tty_struct *tty, if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCMIWAIT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; } @@ -3270,7 +3270,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("%s(%d):block_til_ready on %s\n", __FILE__,__LINE__, tty->driver->name ); - if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ + if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { /* nonblock mode is set or port is not enabled */ port->flags |= ASYNC_NORMAL_ACTIVE; return 0; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index c0a2f5a..1f7d6d9 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1032,7 +1032,7 @@ static int ioctl(struct tty_struct *tty, if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCMIWAIT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; } @@ -3269,7 +3269,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, DBGINFO(("%s block_til_ready\n", tty->driver->name)); - if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ + if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { /* nonblock mode is set or port is not enabled */ port->flags |= ASYNC_NORMAL_ACTIVE; return 0; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 90da0c7..e938799 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1261,7 +1261,7 @@ static int ioctl(struct tty_struct *tty, if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCMIWAIT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; } @@ -3285,7 +3285,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, printk("%s(%d):%s block_til_ready()\n", __FILE__,__LINE__, tty->driver->name ); - if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ + if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { /* nonblock mode is set or port is not enabled */ /* just verify that callout device is not active */ port->flags |= ASYNC_NORMAL_ACTIVE; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 9b04d72..320dc4d 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1070,7 +1070,7 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, if (tty_paranoia_check(tty, inode, "tty_read")) return -EIO; - if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) + if (!tty || tty_io_error(tty)) return -EIO; /* We want to wait for the line discipline to sort out in this @@ -1245,8 +1245,7 @@ static ssize_t tty_write(struct file *file, const char __user *buf, if (tty_paranoia_check(tty, file_inode(file), "tty_write")) return -EIO; - if (!tty || !tty->ops->write || - (test_bit(TTY_IO_ERROR, &tty->flags))) + if (!tty || !tty->ops->write || tty_io_error(tty)) return -EIO; /* Short term debug to catch buggy drivers */ if (tty->ops->write_room == NULL) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index dbcca30..9127c54 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -364,7 +364,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* if non-blocking mode is set we can pass directly to open unless the port has just hung up or is in another error state */ - if (tty->flags & (1 << TTY_IO_ERROR)) { + if (tty_io_error(tty)) { port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } diff --git a/include/linux/tty.h b/include/linux/tty.h index 3b09f23..68d829b 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -360,6 +360,11 @@ static inline void tty_set_flow_change(struct tty_struct *tty, int val) smp_mb(); } +static inline bool tty_io_error(struct tty_struct *tty) +{ + return test_bit(TTY_IO_ERROR, &tty->flags); +} + #ifdef CONFIG_TTY extern void console_init(void); extern void tty_kref_put(struct tty_struct *tty); diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index da126ee..840b82f 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -280,7 +280,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ - if (test_bit(TTY_IO_ERROR, &tty->flags)) { + if (tty_io_error(tty)) { port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index d3687aa..9beb011 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -190,7 +190,7 @@ int ircomm_tty_tiocmget(struct tty_struct *tty) struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned int result; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; result = ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0) @@ -213,7 +213,7 @@ int ircomm_tty_tiocmset(struct tty_struct *tty, { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; IRDA_ASSERT(self != NULL, return -1;); @@ -362,7 +362,7 @@ int ircomm_tty_ioctl(struct tty_struct *tty, if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) + if (tty_io_error(tty)) return -EIO; } -- cgit v1.1 From 97ef38b8210d7459d4cb51668cdf3983772ac6b7 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:11:36 -0700 Subject: tty: Replace TTY_THROTTLED bit tests with tty_throttled() Abstract TTY_THROTTLED bit tests with tty_throttled(). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/char/pcmcia/synclink_cs.c | 2 +- drivers/mmc/card/sdio_uart.c | 2 +- drivers/net/usb/hso.c | 2 +- drivers/staging/fwserial/fwserial.c | 2 +- drivers/staging/speakup/selection.c | 2 +- drivers/tty/amiserial.c | 2 +- drivers/tty/hvc/hvc_console.c | 2 +- drivers/tty/hvc/hvcs.c | 2 +- drivers/tty/hvc/hvsi.c | 2 +- drivers/tty/moxa.c | 2 +- drivers/tty/nozomi.c | 2 +- drivers/tty/serial/serial_core.c | 2 +- drivers/tty/synclink.c | 2 +- drivers/tty/synclink_gt.c | 2 +- drivers/tty/synclinkmp.c | 2 +- drivers/tty/tty_ioctl.c | 4 ++-- drivers/tty/vt/selection.c | 2 +- drivers/usb/gadget/function/u_serial.c | 4 ++-- drivers/usb/serial/digi_acceleport.c | 3 +-- include/linux/tty.h | 5 +++++ net/irda/ircomm/ircomm_tty_ioctl.c | 2 +- 21 files changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 825db42..bcae5bb 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2316,7 +2316,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { info->serial_signals |= SerialSignal_DTR; - if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) info->serial_signals |= SerialSignal_RTS; spin_lock_irqsave(&info->lock, flags); set_signals(info); diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 5415056..5af6fb9 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -895,7 +895,7 @@ static void sdio_uart_set_termios(struct tty_struct *tty, /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { unsigned int mask = TIOCM_DTR; - if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (!(cflag & CRTSCTS) || !tty_throttled(tty)) mask |= TIOCM_RTS; sdio_uart_set_mctrl(port, mask); } diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 111d907..4b44586 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2029,7 +2029,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) tty = tty_port_tty_get(&serial->port); - if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { + if (tty && tty_throttled(tty)) { tty_kref_put(tty); return -1; } diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index 9b23b5c..1f9389d 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -1305,7 +1305,7 @@ static void fwtty_set_termios(struct tty_struct *tty, struct ktermios *old) if ((baud == 0) && (old->c_cflag & CBAUD)) { port->mctrl &= ~(TIOCM_DTR | TIOCM_RTS); } else if ((baud != 0) && !(old->c_cflag & CBAUD)) { - if (C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (C_CRTSCTS(tty) || !tty_throttled(tty)) port->mctrl |= TIOCM_DTR | TIOCM_RTS; else port->mctrl |= TIOCM_DTR; diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c index 41ef099..0149edc 100644 --- a/drivers/staging/speakup/selection.c +++ b/drivers/staging/speakup/selection.c @@ -150,7 +150,7 @@ static void __speakup_paste_selection(struct work_struct *work) add_wait_queue(&vc->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); - if (test_bit(TTY_THROTTLED, &tty->flags)) { + if (tty_throttled(tty)) { schedule(); continue; } diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 183e98e..e68208e 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1342,7 +1342,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { info->MCR |= SER_DTR; - if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) info->MCR |= SER_RTS; local_irq_save(flags); rtsdtr_ctrl(info->MCR); diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index e46d628..209dad8 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -632,7 +632,7 @@ int hvc_poll(struct hvc_struct *hp) goto bail; /* Now check if we can get data (are we throttled ?) */ - if (test_bit(TTY_THROTTLED, &tty->flags)) + if (tty_throttled(tty)) goto throttled; /* If we aren't notifier driven and aren't throttled, we always diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 5997b17..3c4d7c2 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -600,7 +600,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd) hvcs_try_write(hvcsd); - if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) { + if (!tty || tty_throttled(tty)) { hvcsd->todo_mask &= ~(HVCS_READ_MASK); goto bail; } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK))) diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index a75146f..96ce6bd 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -509,7 +509,7 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) } spin_lock_irqsave(&hp->lock, flags); - if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) { + if (tty && hp->n_throttle && !tty_throttled(tty)) { /* we weren't hung up and we weren't throttled, so we can * deliver the rest now */ hvsi_send_overflow(hp); diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 92982d7..ce521d3 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1394,7 +1394,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, tty_wakeup(tty); } - if (inited && !test_bit(TTY_THROTTLED, &tty->flags) && + if (inited && !tty_throttled(tty) && MoxaPortRxQueue(p) > 0) { /* RX */ MoxaPortReadData(p); tty_schedule_flip(&p->port); diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 5cc80b8..d6fd0e8 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -826,7 +826,7 @@ static int receive_data(enum port_type index, struct nozomi *dc) size = __le32_to_cpu(readl(addr)); /* DBG1( "%d bytes port: %d", size, index); */ - if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { + if (tty && tty_throttled(tty)) { DBG1("No room in tty, don't read data, don't ack interrupt, " "disable interrupt"); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 67b3950..64a5c00 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1350,7 +1350,7 @@ static void uart_set_termios(struct tty_struct *tty, /* Handle transition away from B0 status */ else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { unsigned int mask = TIOCM_DTR; - if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (!(cflag & CRTSCTS) || !tty_throttled(tty)) mask |= TIOCM_RTS; uart_set_mctrl(uport, mask); } diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 8b22772..3768e5c 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3049,7 +3049,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { info->serial_signals |= SerialSignal_DTR; - if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) info->serial_signals |= SerialSignal_RTS; spin_lock_irqsave(&info->irq_spinlock,flags); usc_set_serial_signals(info); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 1f7d6d9..ceeaeb7 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -784,7 +784,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { info->signals |= SerialSignal_DTR; - if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) info->signals |= SerialSignal_RTS; spin_lock_irqsave(&info->lock,flags); set_signals(info); diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index e938799..b0cce4b 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -881,7 +881,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { info->serial_signals |= SerialSignal_DTR; - if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) info->serial_signals |= SerialSignal_RTS; spin_lock_irqsave(&info->lock,flags); set_signals(info); diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 23bf5bb..bf36ac9 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -158,7 +158,7 @@ int tty_throttle_safe(struct tty_struct *tty) int ret = 0; mutex_lock(&tty->throttle_mutex); - if (!test_bit(TTY_THROTTLED, &tty->flags)) { + if (!tty_throttled(tty)) { if (tty->flow_change != TTY_THROTTLE_SAFE) ret = 1; else { @@ -189,7 +189,7 @@ int tty_unthrottle_safe(struct tty_struct *tty) int ret = 0; mutex_lock(&tty->throttle_mutex); - if (test_bit(TTY_THROTTLED, &tty->flags)) { + if (tty_throttled(tty)) { if (tty->flow_change != TTY_UNTHROTTLE_SAFE) ret = 1; else { diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 4dd9dd2..368ce18 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -354,7 +354,7 @@ int paste_selection(struct tty_struct *tty) add_wait_queue(&vc->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); - if (test_bit(TTY_THROTTLED, &tty->flags)) { + if (tty_throttled(tty)) { schedule(); continue; } diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 6af145f..3580f19 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -512,7 +512,7 @@ static void gs_rx_push(unsigned long _port) req = list_first_entry(queue, struct usb_request, list); /* leave data queued if tty was rx throttled */ - if (tty && test_bit(TTY_THROTTLED, &tty->flags)) + if (tty && tty_throttled(tty)) break; switch (req->status) { @@ -579,7 +579,7 @@ static void gs_rx_push(unsigned long _port) * from starving ... but it's not clear that case ever happens. */ if (!list_empty(queue) && tty) { - if (!test_bit(TTY_THROTTLED, &tty->flags)) { + if (!tty_throttled(tty)) { if (do_push) tasklet_schedule(&port->push); else diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 16e8e37..6a1df9e 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -699,8 +699,7 @@ static void digi_set_termios(struct tty_struct *tty, /* don't set RTS if using hardware flow control */ /* and throttling input */ modem_signals = TIOCM_DTR; - if (!C_CRTSCTS(tty) || - !test_bit(TTY_THROTTLED, &tty->flags)) + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) modem_signals |= TIOCM_RTS; digi_set_modem_signals(port, modem_signals, 1); } diff --git a/include/linux/tty.h b/include/linux/tty.h index 68d829b..89f9c91 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -365,6 +365,11 @@ static inline bool tty_io_error(struct tty_struct *tty) return test_bit(TTY_IO_ERROR, &tty->flags); } +static inline bool tty_throttled(struct tty_struct *tty) +{ + return test_bit(TTY_THROTTLED, &tty->flags); +} + #ifdef CONFIG_TTY extern void console_init(void); extern void tty_kref_put(struct tty_struct *tty); diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index 9beb011..8d8fd28 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -166,7 +166,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty, /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { self->settings.dte |= IRCOMM_DTR; - if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) self->settings.dte |= IRCOMM_RTS; ircomm_param_request(self, IRCOMM_DTE, TRUE); } -- cgit v1.1 From e4d38f334ad24f80229a8ebab26950de8e8f34d7 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:53:20 -0700 Subject: tty: Define ASYNC_ replacement bits Prepare for relocating kernel private state bits out of tty_port::flags field; tty_port::flags field is not atomic and can become corrupted by concurrent updates. It also suffers from the complication of sharing in a userspace-visible field which must be masked. Define new tty_port::iflags field and new, substitute bit definitions for the former ASYNC_* flags. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 16 +++++++++++++++- include/uapi/linux/tty_flags.h | 9 ++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/linux/tty.h b/include/linux/tty.h index 89f9c91..4e0dbda0 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -228,7 +228,8 @@ struct tty_port { int count; /* Usage count */ wait_queue_head_t open_wait; /* Open waiters */ wait_queue_head_t delta_msr_wait; /* Modem status change */ - unsigned long flags; /* TTY flags ASY_*/ + unsigned long flags; /* User TTY flags ASYNC_ */ + unsigned long iflags; /* Internal flags TTY_PORT_ */ unsigned char console:1, /* port is a console */ low_latency:1; /* optional: tune for latency */ struct mutex mutex; /* Locking */ @@ -242,6 +243,19 @@ struct tty_port { struct kref kref; /* Ref counter */ }; +/* tty_port::iflags bits -- use atomic bit ops */ +#define TTY_PORT_INITIALIZED 0 /* device is initialized */ +#define TTY_PORT_SUSPENDED 1 /* device is suspended */ +#define TTY_PORT_ACTIVE 2 /* device is open */ + +/* + * uart drivers: use the uart_port::status field and the UPSTAT_* defines + * for s/w-based flow control steering and carrier detection status + */ +#define TTY_PORT_CTS_FLOW 3 /* h/w flow control enabled */ +#define TTY_PORT_CHECK_CD 4 /* carrier detect enabled */ + + /* * Where all of the state associated with a tty is kept while the tty * is open. Since the termios state should be kept even if the tty diff --git a/include/uapi/linux/tty_flags.h b/include/uapi/linux/tty_flags.h index 072e41e..8e1a436 100644 --- a/include/uapi/linux/tty_flags.h +++ b/include/uapi/linux/tty_flags.h @@ -32,7 +32,12 @@ #define ASYNCB_MAGIC_MULTIPLIER 16 /* Use special CLK or divisor */ #define ASYNCB_LAST_USER 16 -/* Internal flags used only by kernel */ +/* + * Internal flags used only by kernel (read-only) + * + * WARNING: These flags are no longer used and have been superceded by the + * TTY_PORT_ flags in the iflags field (and not userspace-visible) + */ #define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ #define ASYNCB_SUSPENDED 30 /* Serial port is suspended */ #define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */ @@ -44,6 +49,7 @@ #define ASYNCB_CONS_FLOW 23 /* flow control for console */ #define ASYNCB_FIRST_KERNEL 22 +/* Masks */ #define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY) #define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED) #define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT) @@ -72,6 +78,7 @@ #define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) #define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) +/* These flags are no longer used (and were always masked from userspace) */ #define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED) #define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE) #define ASYNC_BOOT_AUTOCONF (1U << ASYNCB_BOOT_AUTOCONF) -- cgit v1.1 From 5604a98e2f95d6221852960a3363588f40d78e22 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:53:21 -0700 Subject: tty: Replace ASYNC_CTS_FLOW bit and update atomically Replace ASYNC_CTS_FLOW bit in the tty_port::flags field with TTY_PORT_CTS_FLOW bit in the tty_port::iflags field. Add tty_port_set_cts_flow() helper to abstract the atomic bit ops. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/char/pcmcia/synclink_cs.c | 5 +---- drivers/tty/amiserial.c | 6 ++---- drivers/tty/cyclades.c | 10 ++++------ drivers/tty/isicom.c | 6 ++---- drivers/tty/mxser.c | 4 +--- drivers/tty/synclink.c | 7 ++----- drivers/tty/synclink_gt.c | 5 +---- drivers/tty/synclinkmp.c | 5 +---- include/linux/tty.h | 12 ++++++++++-- net/irda/ircomm/ircomm_tty_ioctl.c | 3 +-- 10 files changed, 25 insertions(+), 38 deletions(-) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index bcae5bb..bdf41ac 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1466,10 +1466,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) } info->timeout += HZ/50; /* Add .02 seconds of slop */ - if (cflag & CRTSCTS) - info->port.flags |= ASYNC_CTS_FLOW; - else - info->port.flags &= ~ASYNC_CTS_FLOW; + tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); if (cflag & CLOCAL) info->port.flags &= ~ASYNC_CHECK_CD; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index e68208e..92717b0 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -727,11 +727,9 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, info->IER &= ~UART_IER_MSI; if (port->flags & ASYNC_HARDPPS_CD) info->IER |= UART_IER_MSI; - if (cflag & CRTSCTS) { - port->flags |= ASYNC_CTS_FLOW; + tty_port_set_cts_flow(port, cflag & CRTSCTS); + if (cflag & CRTSCTS) info->IER |= UART_IER_MSI; - } else - port->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) port->flags &= ~ASYNC_CHECK_CD; else { diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index d67e542..1a12776 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2083,13 +2083,11 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) info->cor1 |= CyPARITY_NONE; /* CTS flow control flag */ - if (cflag & CRTSCTS) { - info->port.flags |= ASYNC_CTS_FLOW; + tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); + if (cflag & CRTSCTS) info->cor2 |= CyCtsAE; - } else { - info->port.flags &= ~ASYNC_CTS_FLOW; + else info->cor2 &= ~CyCtsAE; - } if (cflag & CLOCAL) info->port.flags &= ~ASYNC_CHECK_CD; else @@ -2234,7 +2232,7 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) } /* As the HW flow control is done in firmware, the driver doesn't need to care about it */ - info->port.flags &= ~ASYNC_CTS_FLOW; + tty_port_set_cts_flow(&info->port, 0); /* XON/XOFF/XANY flow control flags */ sw_flow = 0; diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 8bf6763..c5f06b5 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -765,11 +765,9 @@ static void isicom_config_port(struct tty_struct *tty) /* flow control settings ...*/ flow_ctrl = 0; - port->port.flags &= ~ASYNC_CTS_FLOW; - if (C_CRTSCTS(tty)) { - port->port.flags |= ASYNC_CTS_FLOW; + tty_port_set_cts_flow(&port->port, C_CRTSCTS(tty)); + if (C_CRTSCTS(tty)) flow_ctrl |= ISICOM_CTSRTS; - } if (I_IXON(tty)) flow_ctrl |= ISICOM_RESPOND_XONXOFF; if (I_IXOFF(tty)) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index f23c2a1..8f3fdad 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -711,8 +711,8 @@ static int mxser_change_speed(struct tty_struct *tty, /* CTS flow control flag and modem status interrupts */ info->IER &= ~UART_IER_MSI; info->MCR &= ~UART_MCR_AFE; + tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); if (cflag & CRTSCTS) { - info->port.flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; if ((info->type == PORT_16550A) || (info->board->chip_flag)) { info->MCR |= UART_MCR_AFE; @@ -744,8 +744,6 @@ static int mxser_change_speed(struct tty_struct *tty, } } } - } else { - info->port.flags &= ~ASYNC_CTS_FLOW; } outb(info->MCR, info->ioaddr + UART_MCR); if (cflag & CLOCAL) { diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 3768e5c..0e42901 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -1966,11 +1966,8 @@ static void mgsl_change_params(struct mgsl_struct *info) } info->timeout += HZ/50; /* Add .02 seconds of slop */ - if (cflag & CRTSCTS) - info->port.flags |= ASYNC_CTS_FLOW; - else - info->port.flags &= ~ASYNC_CTS_FLOW; - + tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); + if (cflag & CLOCAL) info->port.flags &= ~ASYNC_CHECK_CD; else diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index ceeaeb7..5da69d3 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -2576,10 +2576,7 @@ static void change_params(struct slgt_info *info) } info->timeout += HZ/50; /* Add .02 seconds of slop */ - if (cflag & CRTSCTS) - info->port.flags |= ASYNC_CTS_FLOW; - else - info->port.flags &= ~ASYNC_CTS_FLOW; + tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); if (cflag & CLOCAL) info->port.flags &= ~ASYNC_CHECK_CD; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index b0cce4b..7a21491 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -2813,10 +2813,7 @@ static void change_params(SLMP_INFO *info) } info->timeout += HZ/50; /* Add .02 seconds of slop */ - if (cflag & CRTSCTS) - info->port.flags |= ASYNC_CTS_FLOW; - else - info->port.flags &= ~ASYNC_CTS_FLOW; + tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); if (cflag & CLOCAL) info->port.flags &= ~ASYNC_CHECK_CD; diff --git a/include/linux/tty.h b/include/linux/tty.h index 4e0dbda0..989d755b 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -255,7 +255,6 @@ struct tty_port { #define TTY_PORT_CTS_FLOW 3 /* h/w flow control enabled */ #define TTY_PORT_CHECK_CD 4 /* carrier detect enabled */ - /* * Where all of the state associated with a tty is kept while the tty * is open. Since the termios state should be kept even if the tty @@ -561,9 +560,18 @@ static inline struct tty_port *tty_port_get(struct tty_port *port) /* If the cts flow control is enabled, return true. */ static inline bool tty_port_cts_enabled(struct tty_port *port) { - return port->flags & ASYNC_CTS_FLOW; + return test_bit(TTY_PORT_CTS_FLOW, &port->iflags); } +static inline void tty_port_set_cts_flow(struct tty_port *port, bool val) +{ + if (val) + set_bit(TTY_PORT_CTS_FLOW, &port->iflags); + else + clear_bit(TTY_PORT_CTS_FLOW, &port->iflags); +} + + extern struct tty_struct *tty_port_tty_get(struct tty_port *port); extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); extern int tty_port_carrier_raised(struct tty_port *port); diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index 8d8fd28..1220973 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -86,15 +86,14 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self, ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE); /* CTS flow control flag and modem status interrupts */ + tty_port_set_cts_flow(&self->port, cflag & CRTSCTS); if (cflag & CRTSCTS) { - self->port.flags |= ASYNC_CTS_FLOW; self->settings.flow_control |= IRCOMM_RTS_CTS_IN; /* This got me. Bummer. Jean II */ if (self->service_type == IRCOMM_3_WIRE_RAW) net_warn_ratelimited("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__); } else { - self->port.flags &= ~ASYNC_CTS_FLOW; self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN; } if (cflag & CLOCAL) -- cgit v1.1 From 807c8d81f4ec441241cafa3034c58df721fee869 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:53:22 -0700 Subject: tty: Replace ASYNC_NORMAL_ACTIVE bit and update atomically Replace ASYNC_NORMAL_ACTIVE bit in the tty_port::flags field with TTY_PORT_ACTIVE bit in the tty_port::iflags field. Introduce helpers tty_port_set_active() and tty_port_active() to abstract atomic bit ops. Extract state changes from port lock sections, as this usage is broken and confused; the state transitions are protected by the tty lock (which mutually excludes parallel open/close/hangup), and no user tests the active state while holding the port lock. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/i4l/isdn_tty.c | 20 +++++++++----------- drivers/tty/amiserial.c | 2 +- drivers/tty/rocket.c | 5 +++-- drivers/tty/serial/crisv10.c | 8 ++++---- drivers/tty/serial/serial_core.c | 8 ++++---- drivers/tty/synclink.c | 6 +++--- drivers/tty/synclink_gt.c | 6 +++--- drivers/tty/synclinkmp.c | 6 +++--- drivers/tty/tty_port.c | 12 ++++++------ include/linux/tty.h | 12 ++++++++++++ net/irda/ircomm/ircomm_tty.c | 10 +++++----- 11 files changed, 53 insertions(+), 42 deletions(-) diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index f1edc08..d8468f3 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1622,7 +1622,7 @@ isdn_tty_hangup(struct tty_struct *tty) return; isdn_tty_shutdown(info); port->count = 0; - port->flags &= ~ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 0); port->tty = NULL; wake_up_interruptible(&port->open_wait); } @@ -1979,7 +1979,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup) #endif if ( #ifndef FIX_FILE_TRANSFER - (info->port.flags & ASYNC_NORMAL_ACTIVE) && + tty_port_active(&info->port) && #endif (info->isdn_driver == -1) && (info->isdn_channel == -1) && @@ -2018,8 +2018,6 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup) return (wret == 2) ? 3 : 0; } -#define TTY_IS_ACTIVE(info) (info->port.flags & ASYNC_NORMAL_ACTIVE) - int isdn_tty_stat_callback(int i, isdn_ctrl *c) { @@ -2077,7 +2075,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line); #endif - if (TTY_IS_ACTIVE(info)) { + if (tty_port_active(&info->port)) { if (info->dialing == 1) { info->dialing = 2; return 1; @@ -2088,7 +2086,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line); #endif - if (TTY_IS_ACTIVE(info)) { + if (tty_port_active(&info->port)) { if (info->dialing == 1) isdn_tty_modem_result(RESULT_BUSY, info); if (info->dialing > 1) @@ -2118,7 +2116,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) * waiting for it and * set DCD-bit of its modem-status. */ - if (TTY_IS_ACTIVE(info) || + if (tty_port_active(&info->port) || (info->port.blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) { info->msr |= UART_MSR_DCD; @@ -2145,7 +2143,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line); #endif - if (TTY_IS_ACTIVE(info)) { + if (tty_port_active(&info->port)) { #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); #endif @@ -2157,7 +2155,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line); #endif - if (TTY_IS_ACTIVE(info)) { + if (tty_port_active(&info->port)) { if (info->dialing) { info->dialing = 0; info->last_l2 = -1; @@ -2183,14 +2181,14 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) return 1; #ifdef CONFIG_ISDN_TTY_FAX case ISDN_STAT_FAXIND: - if (TTY_IS_ACTIVE(info)) { + if (tty_port_active(&info->port)) { isdn_tty_fax_command(info, c); } break; #endif #ifdef CONFIG_ISDN_AUDIO case ISDN_STAT_AUDIO: - if (TTY_IS_ACTIVE(info)) { + if (tty_port_active(&info->port)) { switch (c->parm.num[0]) { case ISDN_AUDIO_DTMF: if (info->vonline) { diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 92717b0..80d6165 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1493,7 +1493,7 @@ static void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(tty, info); info->tport.count = 0; - info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; + tty_port_set_active(&info->tport, 0); info->tport.tty = NULL; wake_up_interruptible(&info->tport.open_wait); } diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 0b802cd..eb8311b 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -1042,9 +1042,10 @@ static void rp_close(struct tty_struct *tty, struct file *filp) } } spin_lock_irq(&port->lock); - info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE); + port->flags &= ~ASYNC_INITIALIZED; tty->closing = 0; spin_unlock_irq(&port->lock); + tty_port_set_active(port, 0); mutex_unlock(&port->mutex); tty_port_tty_set(port, NULL); @@ -1624,7 +1625,7 @@ static int rp_write(struct tty_struct *tty, /* Write remaining data into the port's xmit_buf */ while (1) { /* Hung up ? */ - if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags)) + if (!tty_port_active(&info->port)) goto end; c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); c = min(c, XMIT_BUF_SIZE - info->xmit_head); diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 5469903..92c8c62 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -3648,8 +3648,8 @@ rs_close(struct tty_struct *tty, struct file * filp) schedule_timeout_interruptible(info->port.close_delay); wake_up_interruptible(&info->port.open_wait); } - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; local_irq_restore(flags); + tty_port_set_active(&info->port, 0); /* port closed */ @@ -3732,7 +3732,7 @@ rs_hangup(struct tty_struct *tty) shutdown(info); info->event = 0; info->port.count = 0; - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + tty_port_set_active(&info->port, 0); info->port.tty = NULL; wake_up_interruptible(&info->port.open_wait); } @@ -3756,7 +3756,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || tty_io_error(tty)) { - info->port.flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(&info->port, 1); return 0; } @@ -3825,7 +3825,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, #endif if (retval) return retval; - info->port.flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(&info->port, 1); return 0; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 64a5c00..2471380 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1418,12 +1418,12 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_change_pm(state, UART_PM_STATE_OFF); spin_lock_irq(&port->lock); } + spin_unlock_irq(&port->lock); + tty_port_set_active(port, 0); /* * Wake up anyone trying to open this port. */ - clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); - spin_unlock_irq(&port->lock); wake_up_interruptible(&port->open_wait); mutex_unlock(&port->mutex); @@ -1501,13 +1501,13 @@ static void uart_hangup(struct tty_struct *tty) pr_debug("uart_hangup(%d)\n", tty->index); mutex_lock(&port->mutex); - if (port->flags & ASYNC_NORMAL_ACTIVE) { + if (tty_port_active(port)) { uart_flush_buffer(tty); uart_shutdown(tty, state); spin_lock_irqsave(&port->lock, flags); port->count = 0; - clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); spin_unlock_irqrestore(&port->lock, flags); + tty_port_set_active(port, 0); tty_port_tty_set(port, NULL); if (!uart_console(state->uart_port)) uart_change_pm(state, UART_PM_STATE_OFF); diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 0e42901..b55f846 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3201,7 +3201,7 @@ static void mgsl_hangup(struct tty_struct *tty) shutdown(info); info->port.count = 0; - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + tty_port_set_active(&info->port, 0); info->port.tty = NULL; wake_up_interruptible(&info->port.open_wait); @@ -3269,7 +3269,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { /* nonblock mode is set or port is not enabled */ - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return 0; } @@ -3338,7 +3338,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, __FILE__,__LINE__, tty->driver->name, port->count ); if (!retval) - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return retval; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 5da69d3..c76f546 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -756,9 +756,9 @@ static void hangup(struct tty_struct *tty) spin_lock_irqsave(&info->port.lock, flags); info->port.count = 0; - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; info->port.tty = NULL; spin_unlock_irqrestore(&info->port.lock, flags); + tty_port_set_active(&info->port, 0); mutex_unlock(&info->port.mutex); wake_up_interruptible(&info->port.open_wait); @@ -3268,7 +3268,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { /* nonblock mode is set or port is not enabled */ - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return 0; } @@ -3325,7 +3325,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, port->blocked_open--; if (!retval) - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); return retval; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 7a21491..95eddc4 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -849,9 +849,9 @@ static void hangup(struct tty_struct *tty) spin_lock_irqsave(&info->port.lock, flags); info->port.count = 0; - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; info->port.tty = NULL; spin_unlock_irqrestore(&info->port.lock, flags); + tty_port_set_active(&info->port, 1); mutex_unlock(&info->port.mutex); wake_up_interruptible(&info->port.open_wait); @@ -3285,7 +3285,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { /* nonblock mode is set or port is not enabled */ /* just verify that callout device is not active */ - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return 0; } @@ -3352,7 +3352,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, __FILE__,__LINE__, tty->driver->name, port->count ); if (!retval) - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return retval; } diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 9127c54..130c8cf 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -236,12 +236,12 @@ void tty_port_hangup(struct tty_port *port) spin_lock_irqsave(&port->lock, flags); port->count = 0; - port->flags &= ~ASYNC_NORMAL_ACTIVE; tty = port->tty; if (tty) set_bit(TTY_IO_ERROR, &tty->flags); port->tty = NULL; spin_unlock_irqrestore(&port->lock, flags); + tty_port_set_active(port, 0); tty_port_shutdown(port, tty); tty_kref_put(tty); wake_up_interruptible(&port->open_wait); @@ -365,14 +365,14 @@ int tty_port_block_til_ready(struct tty_port *port, /* if non-blocking mode is set we can pass directly to open unless the port has just hung up or is in another error state */ if (tty_io_error(tty)) { - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return 0; } if (filp->f_flags & O_NONBLOCK) { /* Indicate we are open */ if (C_BAUD(tty)) tty_port_raise_dtr_rts(port); - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return 0; } @@ -430,9 +430,9 @@ int tty_port_block_til_ready(struct tty_port *port, if (!tty_hung_up_p(filp)) port->count++; port->blocked_open--; - if (retval == 0) - port->flags |= ASYNC_NORMAL_ACTIVE; spin_unlock_irqrestore(&port->lock, flags); + if (retval == 0) + tty_port_set_active(port, 1); return retval; } EXPORT_SYMBOL(tty_port_block_til_ready); @@ -514,8 +514,8 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) spin_lock_irqsave(&port->lock, flags); wake_up_interruptible(&port->open_wait); } - port->flags &= ~ASYNC_NORMAL_ACTIVE; spin_unlock_irqrestore(&port->lock, flags); + tty_port_set_active(port, 0); } EXPORT_SYMBOL(tty_port_close_end); diff --git a/include/linux/tty.h b/include/linux/tty.h index 989d755b..dbeeb86 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -571,6 +571,18 @@ static inline void tty_port_set_cts_flow(struct tty_port *port, bool val) clear_bit(TTY_PORT_CTS_FLOW, &port->iflags); } +static inline bool tty_port_active(struct tty_port *port) +{ + return test_bit(TTY_PORT_ACTIVE, &port->iflags); +} + +static inline void tty_port_set_active(struct tty_port *port, bool val) +{ + if (val) + set_bit(TTY_PORT_ACTIVE, &port->iflags); + else + clear_bit(TTY_PORT_ACTIVE, &port->iflags); +} extern struct tty_struct *tty_port_tty_get(struct tty_port *port); extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 840b82f..681fe0b 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -281,7 +281,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, * then make the check up front and then exit. */ if (tty_io_error(tty)) { - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return 0; } @@ -289,7 +289,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, /* nonblock mode is set */ if (C_BAUD(tty)) tty_port_raise_dtr_rts(port); - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); pr_debug("%s(), O_NONBLOCK requested!\n", __func__); return 0; } @@ -365,7 +365,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, __FILE__, __LINE__, tty->driver->name, port->count); if (!retval) - port->flags |= ASYNC_NORMAL_ACTIVE; + tty_port_set_active(port, 1); return retval; } @@ -925,7 +925,6 @@ static void ircomm_tty_hangup(struct tty_struct *tty) ircomm_tty_shutdown(self); spin_lock_irqsave(&port->lock, flags); - port->flags &= ~ASYNC_NORMAL_ACTIVE; if (port->tty) { set_bit(TTY_IO_ERROR, &port->tty->flags); tty_kref_put(port->tty); @@ -933,6 +932,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty) port->tty = NULL; port->count = 0; spin_unlock_irqrestore(&port->lock, flags); + tty_port_set_active(port, 0); wake_up_interruptible(&port->open_wait); } @@ -1267,7 +1267,7 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) seq_printf(m, "%cASYNC_LOW_LATENCY", sep); sep = '|'; } - if (self->port.flags & ASYNC_NORMAL_ACTIVE) { + if (tty_port_active(&self->port)) { seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep); sep = '|'; } -- cgit v1.1 From 2d68655d15bc99981394f7caa769a14b03cac131 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:53:23 -0700 Subject: tty: Replace ASYNC_CHECK_CD and update atomically Replace ASYNC_CHECK_CD bit in the tty_port::flags field with TTY_PORT_CHECK_CD bit in the tty_port::iflags field. Introduce helpers tty_port_set_check_carrier() and tty_port_check_carrier() to abstract the atomic bit ops. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/char/pcmcia/synclink_cs.c | 8 ++------ drivers/isdn/i4l/isdn_tty.c | 8 ++------ drivers/tty/amiserial.c | 9 +++------ drivers/tty/cyclades.c | 14 ++++---------- drivers/tty/isicom.c | 7 ++----- drivers/tty/mxser.c | 9 +++------ drivers/tty/synclink.c | 8 ++------ drivers/tty/synclink_gt.c | 8 ++------ drivers/tty/synclinkmp.c | 8 ++------ include/linux/tty.h | 13 +++++++++++++ net/irda/ircomm/ircomm_tty.c | 4 ++-- net/irda/ircomm/ircomm_tty_attach.c | 2 +- net/irda/ircomm/ircomm_tty_ioctl.c | 5 +---- 13 files changed, 39 insertions(+), 64 deletions(-) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index bdf41ac..bf54f4e 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1101,7 +1101,7 @@ static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if (info->port.flags & ASYNC_CHECK_CD) { + if (tty_port_check_carrier(&info->port)) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s CD now %s...", info->device_name, (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); @@ -1467,11 +1467,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) info->timeout += HZ/50; /* Add .02 seconds of slop */ tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); - - if (cflag & CLOCAL) - info->port.flags &= ~ASYNC_CHECK_CD; - else - info->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); /* process tty input control flags */ diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index d8468f3..023a350a 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1043,11 +1043,7 @@ isdn_tty_change_speed(modem_info *info) if (!(cflag & PARODD)) cval |= UART_LCR_EPAR; - if (cflag & CLOCAL) - port->flags &= ~ASYNC_CHECK_CD; - else { - port->flags |= ASYNC_CHECK_CD; - } + tty_port_set_check_carrier(port, ~cflag & CLOCAL); } static int @@ -2526,7 +2522,7 @@ isdn_tty_modem_result(int code, modem_info *info) if (info->closing || (!info->port.tty)) return; - if (info->port.flags & ASYNC_CHECK_CD) + if (tty_port_check_carrier(&info->port)) tty_hangup(info->port.tty); } } diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 80d6165..b4ab97d 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -398,7 +398,7 @@ static void check_modem_status(struct serial_state *info) wake_up_interruptible(&port->delta_msr_wait); } - if ((port->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { + if (tty_port_check_carrier(port) && (dstatus & SER_DCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off"); @@ -730,12 +730,9 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, tty_port_set_cts_flow(port, cflag & CRTSCTS); if (cflag & CRTSCTS) info->IER |= UART_IER_MSI; - if (cflag & CLOCAL) - port->flags &= ~ASYNC_CHECK_CD; - else { - port->flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(port, ~cflag & CLOCAL); + if (~cflag & CLOCAL) info->IER |= UART_IER_MSI; - } /* TBD: * Does clearing IER_MSI imply that we should disable the VBL interrupt ? */ diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 1a12776..9d1e19b 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -714,7 +714,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, wake_up_interruptible(&info->port.delta_msr_wait); } - if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) { + if ((mdm_change & CyDCD) && tty_port_check_carrier(&info->port)) { if (mdm_status & CyDCD) wake_up_interruptible(&info->port.open_wait); else @@ -1119,7 +1119,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) case C_CM_MDCD: info->icount.dcd++; delta_count++; - if (info->port.flags & ASYNC_CHECK_CD) { + if (tty_port_check_carrier(&info->port)) { u32 dcd = fw_ver > 241 ? param : readl(&info->u.cyz.ch_ctrl->rs_status); if (dcd & C_RS_DCD) @@ -2088,10 +2088,7 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) info->cor2 |= CyCtsAE; else info->cor2 &= ~CyCtsAE; - if (cflag & CLOCAL) - info->port.flags &= ~ASYNC_CHECK_CD; - else - info->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); /*********************************************** The hardware option, CyRtsAO, presents RTS when @@ -2250,10 +2247,7 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) } /* CD sensitivity */ - if (cflag & CLOCAL) - info->port.flags &= ~ASYNC_CHECK_CD; - else - info->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); if (baud == 0) { /* baud rate is zero, turn off line */ cy_writel(&ch_ctrl->rs_control, diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index c5f06b5..0b2bae1 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -577,7 +577,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) header = inw(base); switch (header & 0xff) { case 0: /* Change in EIA signals */ - if (port->port.flags & ASYNC_CHECK_CD) { + if (tty_port_check_carrier(&port->port)) { if (port->status & ISI_DCD) { if (!(header & ISI_DCD)) { /* Carrier has been lost */ @@ -758,10 +758,7 @@ static void isicom_config_port(struct tty_struct *tty) outw(channel_setup, base); InterruptTheCard(base); } - if (C_CLOCAL(tty)) - port->port.flags &= ~ASYNC_CHECK_CD; - else - port->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&port->port, !C_CLOCAL(tty)); /* flow control settings ...*/ flow_ctrl = 0; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8f3fdad..ab618ef 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -746,12 +746,9 @@ static int mxser_change_speed(struct tty_struct *tty, } } outb(info->MCR, info->ioaddr + UART_MCR); - if (cflag & CLOCAL) { - info->port.flags &= ~ASYNC_CHECK_CD; - } else { - info->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); + if (~cflag & CLOCAL) info->IER |= UART_IER_MSI; - } outb(info->IER, info->ioaddr + UART_IER); /* @@ -824,7 +821,7 @@ static void mxser_check_modem_status(struct tty_struct *tty, port->mon_data.modem_status = status; wake_up_interruptible(&port->port.delta_msr_wait); - if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { + if (tty_port_check_carrier(&port->port) && (status & UART_MSR_DDCD)) { if (status & UART_MSR_DCD) wake_up_interruptible(&port->port.open_wait); } diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index b55f846..b67b54a 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -1340,7 +1340,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if ( (info->port.flags & ASYNC_CHECK_CD) && + if (tty_port_check_carrier(&info->port) && (status & MISCSTATUS_DCD_LATCHED) ) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s CD now %s...", info->device_name, @@ -1967,11 +1967,7 @@ static void mgsl_change_params(struct mgsl_struct *info) info->timeout += HZ/50; /* Add .02 seconds of slop */ tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); - - if (cflag & CLOCAL) - info->port.flags &= ~ASYNC_CHECK_CD; - else - info->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); /* process tty input control flags */ diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index c76f546..333652a 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -2080,7 +2080,7 @@ static void dcd_change(struct slgt_info *info, unsigned short status) wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; - if (info->port.flags & ASYNC_CHECK_CD) { + if (tty_port_check_carrier(&info->port)) { if (info->signals & SerialSignal_DCD) wake_up_interruptible(&info->port.open_wait); else { @@ -2577,11 +2577,7 @@ static void change_params(struct slgt_info *info) info->timeout += HZ/50; /* Add .02 seconds of slop */ tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); - - if (cflag & CLOCAL) - info->port.flags &= ~ASYNC_CHECK_CD; - else - info->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); /* process tty input control flags */ diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 95eddc4..17bab5f 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -2463,7 +2463,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status ) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if ( (info->port.flags & ASYNC_CHECK_CD) && + if (tty_port_check_carrier(&info->port) && (status & MISCSTATUS_DCD_LATCHED) ) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s CD now %s...", info->device_name, @@ -2814,11 +2814,7 @@ static void change_params(SLMP_INFO *info) info->timeout += HZ/50; /* Add .02 seconds of slop */ tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); - - if (cflag & CLOCAL) - info->port.flags &= ~ASYNC_CHECK_CD; - else - info->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); /* process tty input control flags */ diff --git a/include/linux/tty.h b/include/linux/tty.h index dbeeb86..4254dfb 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -584,6 +584,19 @@ static inline void tty_port_set_active(struct tty_port *port, bool val) clear_bit(TTY_PORT_ACTIVE, &port->iflags); } +static inline bool tty_port_check_carrier(struct tty_port *port) +{ + return test_bit(TTY_PORT_CHECK_CD, &port->iflags); +} + +static inline void tty_port_set_check_carrier(struct tty_port *port, bool val) +{ + if (val) + set_bit(TTY_PORT_CHECK_CD, &port->iflags); + else + clear_bit(TTY_PORT_CHECK_CD, &port->iflags); +} + extern struct tty_struct *tty_port_tty_get(struct tty_port *port); extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); extern int tty_port_carrier_raised(struct tty_port *port); diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 681fe0b..5b7ce59 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -999,7 +999,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) if (status & IRCOMM_DCE_DELTA_ANY) { /*wake_up_interruptible(&self->delta_msr_wait);*/ } - if ((self->port.flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) { + if (tty_port_check_carrier(&self->port) && (status & IRCOMM_DELTA_CD)) { pr_debug("%s(), ircomm%d CD now %s...\n", __func__ , self->line, (status & IRCOMM_CD) ? "on" : "off"); @@ -1255,7 +1255,7 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) seq_printf(m, "%cASYNC_CTS_FLOW", sep); sep = '|'; } - if (self->port.flags & ASYNC_CHECK_CD) { + if (tty_port_check_carrier(&self->port)) { seq_printf(m, "%cASYNC_CHECK_CD", sep); sep = '|'; } diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index 61137f8..0a41101 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -968,7 +968,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); ircomm_tty_start_watchdog_timer(self, 3*HZ); - if (self->port.flags & ASYNC_CHECK_CD) { + if (tty_port_check_carrier(&self->port)) { /* Drop carrier */ self->settings.dce = IRCOMM_DELTA_CD; ircomm_tty_check_modem_status(self); diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index 1220973..e24724d 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -96,10 +96,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self, } else { self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN; } - if (cflag & CLOCAL) - self->port.flags &= ~ASYNC_CHECK_CD; - else - self->port.flags |= ASYNC_CHECK_CD; + tty_port_set_check_carrier(&self->port, ~cflag & CLOCAL); #if 0 /* * Set up parity check flag -- cgit v1.1 From 80f02d5424301bf4df195d09b1a664f394435851 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:53:24 -0700 Subject: tty: Replace ASYNC_SUSPENDED bit and update atomically Replace ASYNC_SUSPENDED bit in the tty_port::flags field with TTY_PORT_SUSPENDED bit in the tty_port::iflags field. Introduce helpers tty_port_set_suspended() and tty_port_suspended() to abstract atomic bit ops. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/char/con3215.c | 12 ++++++------ drivers/tty/serial/serial_core.c | 8 ++++---- include/linux/tty.h | 13 +++++++++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index e7e078b..114fe28 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -289,7 +289,7 @@ static void raw3215_timeout(unsigned long __data) spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_TIMER_RUNS; - if (!(raw->port.flags & ASYNC_SUSPENDED)) { + if (!tty_port_suspended(&raw->port)) { raw3215_mk_write_req(raw); raw3215_start_io(raw); if ((raw->queued_read || raw->queued_write) && @@ -312,7 +312,7 @@ static void raw3215_timeout(unsigned long __data) static inline void raw3215_try_io(struct raw3215_info *raw) { if (!(raw->port.flags & ASYNC_INITIALIZED) || - (raw->port.flags & ASYNC_SUSPENDED)) + tty_port_suspended(&raw->port)) return; if (raw->queued_read != NULL) raw3215_start_io(raw); @@ -494,7 +494,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) /* While console is frozen for suspend we have no other * choice but to drop message from the buffer to make * room for even more messages. */ - if (raw->port.flags & ASYNC_SUSPENDED) { + if (tty_port_suspended(&raw->port)) { raw3215_drop_line(raw); continue; } @@ -773,7 +773,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev) raw = dev_get_drvdata(&cdev->dev); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_make_room(raw, RAW3215_BUFFER_SIZE); - raw->port.flags |= ASYNC_SUSPENDED; + tty_port_set_suspended(&raw->port, 1); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); return 0; } @@ -786,7 +786,7 @@ static int raw3215_pm_start(struct ccw_device *cdev) /* Allow I/O again and flush output buffer. */ raw = dev_get_drvdata(&cdev->dev); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); - raw->port.flags &= ~ASYNC_SUSPENDED; + tty_port_set_suspended(&raw->port, 0); raw->flags |= RAW3215_FLUSHING; raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; @@ -859,7 +859,7 @@ static void con3215_flush(void) unsigned long flags; raw = raw3215[0]; /* console 3215 is the first one */ - if (raw->port.flags & ASYNC_SUSPENDED) + if (tty_port_suspended(&raw->port)) /* The console is still frozen for suspend. */ if (ccw_device_force_console(raw->cdev)) /* Forcing didn't work, no panic message .. */ diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 2471380..9336067 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -249,7 +249,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) * a DCD drop (hangup) at just the right time. Clear suspended bit so * we don't try to resume a port that has been shutdown. */ - clear_bit(ASYNCB_SUSPENDED, &port->flags); + tty_port_set_suspended(port, 0); /* * Free the transmit buffer page. @@ -2007,7 +2007,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) const struct uart_ops *ops = uport->ops; int tries; - set_bit(ASYNCB_SUSPENDED, &port->flags); + tty_port_set_suspended(port, 1); clear_bit(ASYNCB_INITIALIZED, &port->flags); spin_lock_irq(&uport->lock); @@ -2088,7 +2088,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) console_start(uport->cons); } - if (port->flags & ASYNC_SUSPENDED) { + if (tty_port_suspended(port)) { const struct uart_ops *ops = uport->ops; int ret; @@ -2118,7 +2118,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) } } - clear_bit(ASYNCB_SUSPENDED, &port->flags); + tty_port_set_suspended(port, 0); } mutex_unlock(&port->mutex); diff --git a/include/linux/tty.h b/include/linux/tty.h index 4254dfb..7ac5add 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -597,6 +597,19 @@ static inline void tty_port_set_check_carrier(struct tty_port *port, bool val) clear_bit(TTY_PORT_CHECK_CD, &port->iflags); } +static inline bool tty_port_suspended(struct tty_port *port) +{ + return test_bit(TTY_PORT_SUSPENDED, &port->iflags); +} + +static inline void tty_port_set_suspended(struct tty_port *port, bool val) +{ + if (val) + set_bit(TTY_PORT_SUSPENDED, &port->iflags); + else + clear_bit(TTY_PORT_SUSPENDED, &port->iflags); +} + extern struct tty_struct *tty_port_tty_get(struct tty_port *port); extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); extern int tty_port_carrier_raised(struct tty_port *port); -- cgit v1.1 From d41861ca19c9e96f12a4f1ebbc8255d00909a232 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:53:25 -0700 Subject: tty: Replace ASYNC_INITIALIZED bit and update atomically Replace ASYNC_INITIALIZED bit in the tty_port::flags field with TTY_PORT_INITIALIZED bit in the tty_port::iflags field. Introduce helpers tty_port_set_initialized() and tty_port_initialized() to abstract atomic bit ops. Note: the transforms for test_and_set_bit() and test_and_clear_bit() are unnecessary as the state transitions are already mutually exclusive; the tty lock prevents concurrent open/close/hangup. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/char/pcmcia/synclink_cs.c | 12 +++++----- drivers/ipack/devices/ipoctal.c | 5 ++--- drivers/isdn/i4l/isdn_tty.c | 10 ++++----- drivers/s390/char/con3215.c | 12 +++++----- drivers/tty/amiserial.c | 14 ++++++------ drivers/tty/cyclades.c | 14 ++++++------ drivers/tty/isicom.c | 6 ++--- drivers/tty/moxa.c | 10 ++++----- drivers/tty/mxser.c | 14 +++++------- drivers/tty/n_gsm.c | 8 +++---- drivers/tty/rocket.c | 10 ++++----- drivers/tty/serial/crisv10.c | 17 +++++++------- drivers/tty/serial/serial_core.c | 24 +++++++++++--------- drivers/tty/synclink.c | 46 ++++++++++++++++++-------------------- drivers/tty/synclink_gt.c | 16 ++++++------- drivers/tty/synclinkmp.c | 16 ++++++------- drivers/tty/tty_port.c | 13 ++++++----- drivers/usb/class/cdc-acm.c | 4 ++-- drivers/usb/serial/console.c | 4 ++-- drivers/usb/serial/generic.c | 6 ++--- drivers/usb/serial/mxuport.c | 6 ++--- drivers/usb/serial/sierra.c | 4 ++-- drivers/usb/serial/usb-serial.c | 2 +- drivers/usb/serial/usb_wwan.c | 4 ++-- include/linux/tty.h | 13 +++++++++++ net/irda/ircomm/ircomm_tty.c | 15 +++++++------ net/irda/ircomm/ircomm_tty_ioctl.c | 2 +- 27 files changed, 157 insertions(+), 150 deletions(-) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index bf54f4e..345ca7c 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1272,7 +1272,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):startup(%s)\n", __FILE__, __LINE__, info->device_name); - if (info->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&info->port)) return 0; if (!info->tx_buf) { @@ -1311,7 +1311,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty) if (tty) clear_bit(TTY_IO_ERROR, &tty->flags); - info->port.flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 1); return 0; } @@ -1322,7 +1322,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) { unsigned long flags; - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) return; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1361,7 +1361,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) if (tty) set_bit(TTY_IO_ERROR, &tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 0); } static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) @@ -2338,7 +2338,7 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp) if (tty_port_close_start(port, tty, filp) == 0) goto cleanup; - if (port->flags & ASYNC_INITIALIZED) + if (tty_port_initialized(port)) mgslpc_wait_until_sent(tty, info->timeout); mgslpc_flush_buffer(tty); @@ -2371,7 +2371,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent")) return; - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) goto exit; orig_jiffies = jiffies; diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c index 035d544..75dd15d 100644 --- a/drivers/ipack/devices/ipoctal.c +++ b/drivers/ipack/devices/ipoctal.c @@ -629,8 +629,7 @@ static void ipoctal_hangup(struct tty_struct *tty) tty_port_hangup(&channel->tty_port); ipoctal_reset_channel(channel); - - clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags); + tty_port_set_initialized(&channel->tty_port, 0); wake_up_interruptible(&channel->tty_port.open_wait); } @@ -642,7 +641,7 @@ static void ipoctal_shutdown(struct tty_struct *tty) return; ipoctal_reset_channel(channel); - clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags); + tty_port_set_initialized(&channel->tty_port, 0); } static void ipoctal_cleanup(struct tty_struct *tty) diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 023a350a..63eaa0a 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1049,7 +1049,7 @@ isdn_tty_change_speed(modem_info *info) static int isdn_tty_startup(modem_info *info) { - if (info->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&info->port)) return 0; isdn_lock_drivers(); #ifdef ISDN_DEBUG_MODEM_OPEN @@ -1066,7 +1066,7 @@ isdn_tty_startup(modem_info *info) */ isdn_tty_change_speed(info); - info->port.flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 1); info->msr |= (UART_MSR_DSR | UART_MSR_CTS); info->send_outstanding = 0; return 0; @@ -1079,7 +1079,7 @@ isdn_tty_startup(modem_info *info) static void isdn_tty_shutdown(modem_info *info) { - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) return; #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line); @@ -1099,7 +1099,7 @@ isdn_tty_shutdown(modem_info *info) if (info->port.tty) set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 0); } /* isdn_tty_write() is the main send-routine. It is called from the upper @@ -1577,7 +1577,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp) * interrupt driver to stop checking the data ready bit in the * line status register. */ - if (port->flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(port)) { tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ /* * Before we drop DTR, make sure the UART transmitter diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 114fe28..931d10e 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -311,8 +311,7 @@ static void raw3215_timeout(unsigned long __data) */ static inline void raw3215_try_io(struct raw3215_info *raw) { - if (!(raw->port.flags & ASYNC_INITIALIZED) || - tty_port_suspended(&raw->port)) + if (!tty_port_initialized(&raw->port) || tty_port_suspended(&raw->port)) return; if (raw->queued_read != NULL) raw3215_start_io(raw); @@ -616,10 +615,10 @@ static int raw3215_startup(struct raw3215_info *raw) { unsigned long flags; - if (raw->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&raw->port)) return 0; raw->line_pos = 0; - raw->port.flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(&raw->port, 1); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_try_io(raw); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -635,8 +634,7 @@ static void raw3215_shutdown(struct raw3215_info *raw) DECLARE_WAITQUEUE(wait, current); unsigned long flags; - if (!(raw->port.flags & ASYNC_INITIALIZED) || - (raw->flags & RAW3215_FIXED)) + if (!tty_port_initialized(&raw->port) || (raw->flags & RAW3215_FIXED)) return; /* Wait for outstanding requests, then free irq */ spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); @@ -650,7 +648,7 @@ static void raw3215_shutdown(struct raw3215_info *raw) spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); remove_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_RUNNING); - raw->port.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&raw->port, 1); } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b4ab97d..208f573 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -525,7 +525,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info) local_irq_save(flags); - if (port->flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(port)) { free_page(page); goto errout; } @@ -586,7 +586,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info) */ change_speed(tty, info, NULL); - port->flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(port, 1); local_irq_restore(flags); return 0; @@ -604,7 +604,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) unsigned long flags; struct serial_state *state; - if (!(info->tport.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->tport)) return; state = info; @@ -645,7 +645,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) set_bit(TTY_IO_ERROR, &tty->flags); - info->tport.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&info->tport, 0); local_irq_restore(flags); } @@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: - if (port->flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(port)) { if (change_spd) { if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) tty->alt_speed = 57600; @@ -1390,7 +1390,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * line status register. */ state->read_status_mask &= ~UART_LSR_DR; - if (port->flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(port)) { /* disable receive interrupts */ custom.intena = IF_RBF; mb(); @@ -1538,7 +1538,7 @@ static inline void line_info(struct seq_file *m, int line, local_irq_save(flags); status = ciab.pra; - control = (state->tport.flags & ASYNC_INITIALIZED) ? state->MCR : status; + control = tty_port_initialized(&state->tport) ? state->MCR : status; local_irq_restore(flags); stat_buf[0] = 0; diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 9d1e19b..3840d6b 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1279,7 +1279,7 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) spin_lock_irqsave(&card->card_lock, flags); - if (info->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&info->port)) goto errout; if (!info->type) { @@ -1364,7 +1364,7 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) /* enable send, recv, modem !!! */ } - info->port.flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 1); clear_bit(TTY_IO_ERROR, &tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; @@ -1424,7 +1424,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) struct cyclades_card *card; unsigned long flags; - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) return; card = info->card; @@ -1448,7 +1448,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) some later date (after testing)!!! */ set_bit(TTY_IO_ERROR, &tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 0); spin_unlock_irqrestore(&card->card_lock, flags); } else { #ifdef CY_DEBUG_OPEN @@ -1473,7 +1473,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) tty_port_lower_dtr_rts(&info->port); set_bit(TTY_IO_ERROR, &tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 0); spin_unlock_irqrestore(&card->card_lock, flags); } @@ -1711,7 +1711,7 @@ static void cy_do_close(struct tty_port *port) /* Stop accepting input */ cyy_writeb(info, CyCAR, channel & 0x03); cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData); - if (info->port.flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(&info->port)) { /* Waiting for on-board buffers to be empty before closing the port */ spin_unlock_irqrestore(&card->card_lock, flags); @@ -2334,7 +2334,7 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, info->port.closing_wait = new_serial.closing_wait * HZ / 100; check_and_exit: - if (info->port.flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(&info->port)) { cy_set_line_char(info, tty); ret = 0; } else { diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 0b2bae1..b70187b 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -438,8 +438,8 @@ static void isicom_tx(unsigned long _data) for (; count > 0; count--, port++) { /* port not active or tx disabled to force flow control */ - if (!(port->port.flags & ASYNC_INITIALIZED) || - !(port->status & ISI_TXOK)) + if (!tty_port_initialized(&port->port) || + !(port->status & ISI_TXOK)) continue; txcount = min_t(short, TX_SIZE, port->xmit_cnt); @@ -553,7 +553,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } port = card->ports + channel; - if (!(port->port.flags & ASYNC_INITIALIZED)) { + if (!tty_port_initialized(&port->port)) { outw(0x0000, base+0x04); /* enable interrupts */ spin_unlock(&card->card_lock); return IRQ_HANDLED; diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index ce521d3..60d37b2 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -912,7 +912,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd) /* pci hot-un-plug support */ for (a = 0; a < brd->numPorts; a++) - if (brd->ports[a].port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&brd->ports[a].port)) tty_port_tty_hangup(&brd->ports[a].port, false); for (a = 0; a < MAX_PORTS_PER_BOARD; a++) @@ -921,7 +921,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd) while (1) { opened = 0; for (a = 0; a < brd->numPorts; a++) - if (brd->ports[a].port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&brd->ports[a].port)) opened++; mutex_unlock(&moxa_openlock); if (!opened) @@ -1192,13 +1192,13 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) tty->driver_data = ch; tty_port_tty_set(&ch->port, tty); mutex_lock(&ch->port.mutex); - if (!(ch->port.flags & ASYNC_INITIALIZED)) { + if (!tty_port_initialized(&ch->port)) { ch->statusflags = 0; moxa_set_tty_param(tty, &tty->termios); MoxaPortLineCtrl(ch, 1, 1); MoxaPortEnable(ch); MoxaSetFifo(ch, ch->type == PORT_16550A); - ch->port.flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(&ch->port, 1); } mutex_unlock(&ch->port.mutex); mutex_unlock(&moxa_openlock); @@ -1379,7 +1379,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, { struct tty_struct *tty = tty_port_tty_get(&p->port); void __iomem *ofsAddr; - unsigned int inited = p->port.flags & ASYNC_INITIALIZED; + unsigned int inited = tty_port_initialized(&p->port); u16 intr; if (tty) { diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index ab618ef..7e8c27b 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1081,12 +1081,10 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) mutex_lock(&port->mutex); mxser_close_port(port); mxser_flush_buffer(tty); - if (test_bit(ASYNCB_INITIALIZED, &port->flags)) { - if (C_HUPCL(tty)) - tty_port_lower_dtr_rts(port); - } + if (tty_port_initialized(port) && C_HUPCL(tty)) + tty_port_lower_dtr_rts(port); mxser_shutdown_port(port); - clear_bit(ASYNCB_INITIALIZED, &port->flags); + tty_port_set_initialized(port, 0); mutex_unlock(&port->mutex); info->closing = 0; /* Right now the tty_port set is done outside of the close_end helper @@ -1282,7 +1280,7 @@ static int mxser_set_serial_info(struct tty_struct *tty, process_txrx_fifo(info); - if (test_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (tty_port_initialized(port)) { if (flags != (port->flags & ASYNC_SPD_MASK)) { spin_lock_irqsave(&info->slock, sl_flags); mxser_change_speed(tty, NULL); @@ -1291,7 +1289,7 @@ static int mxser_set_serial_info(struct tty_struct *tty, } else { retval = mxser_activate(port, tty); if (retval == 0) - set_bit(ASYNCB_INITIALIZED, &port->flags); + tty_port_set_initialized(port, 1); } return retval; } @@ -2251,7 +2249,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) iir &= MOXA_MUST_IIR_MASK; tty = tty_port_tty_get(&port->port); if (!tty || port->closing || - !(port->port.flags & ASYNC_INITIALIZED)) { + !tty_port_initialized(&port->port)) { status = inb(port->ioaddr + UART_LSR); outb(0x27, port->ioaddr + UART_FCR); inb(port->ioaddr + UART_MSR); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 365dfd8..9f7a7bb 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2949,7 +2949,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) dlci->modem_rx = 0; /* We could in theory open and close before we wait - eg if we get a DM straight back. This is ok as that will have caused a hangup */ - set_bit(ASYNCB_INITIALIZED, &port->flags); + tty_port_set_initialized(port, 1); /* Start sending off SABM messages */ gsm_dlci_begin_open(dlci); /* And wait for virtual carrier */ @@ -2972,10 +2972,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp) if (tty_port_close_start(&dlci->port, tty, filp) == 0) return; gsm_dlci_begin_close(dlci); - if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) { - if (C_HUPCL(tty)) - tty_port_lower_dtr_rts(&dlci->port); - } + if (tty_port_initialized(&dlci->port) && C_HUPCL(tty)) + tty_port_lower_dtr_rts(&dlci->port); tty_port_close_end(&dlci->port, tty); tty_port_tty_set(&dlci->port, NULL); return; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index eb8311b..7f3b1db 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -495,7 +495,7 @@ static void rp_handle_port(struct r_port *info) if (!info) return; - if ((info->port.flags & ASYNC_INITIALIZED) == 0) { + if (!tty_port_initialized(&info->port)) { printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " "info->flags & NOT_INIT\n"); return; @@ -920,7 +920,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) /* * Info->count is now 1; so it's safe to sleep now. */ - if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (!tty_port_initialized(port)) { cp = &info->channel; sSetRxTrigger(cp, TRIG_1); if (sGetChanStatus(cp) & CD_ACT) @@ -944,7 +944,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) sEnRxFIFO(cp); sEnTransmit(cp); - set_bit(ASYNCB_INITIALIZED, &info->port.flags); + tty_port_set_initialized(&info->port, 1); /* * Set up the tty->alt_speed kludge @@ -1042,9 +1042,9 @@ static void rp_close(struct tty_struct *tty, struct file *filp) } } spin_lock_irq(&port->lock); - port->flags &= ~ASYNC_INITIALIZED; tty->closing = 0; spin_unlock_irq(&port->lock); + tty_port_set_initialized(port, 0); tty_port_set_active(port, 0); mutex_unlock(&port->mutex); tty_port_tty_set(port, NULL); @@ -1513,7 +1513,7 @@ static void rp_hangup(struct tty_struct *tty) sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); - clear_bit(ASYNCB_INITIALIZED, &info->port.flags); + tty_port_set_initialized(&info->port, 0); wake_up_interruptible(&info->port.open_wait); } diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 92c8c62..315c849 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -2599,7 +2599,7 @@ startup(struct e100_serial * info) /* if it was already initialized, skip this */ - if (info->port.flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(&info->port)) { local_irq_restore(flags); free_page(xmit_page); return 0; @@ -2703,7 +2703,7 @@ startup(struct e100_serial * info) e100_rts(info, 1); e100_dtr(info, 1); - info->port.flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 1); local_irq_restore(flags); return 0; @@ -2745,7 +2745,7 @@ shutdown(struct e100_serial * info) info->tr_running = 0; } - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) return; #ifdef SERIAL_DEBUG_OPEN @@ -2776,7 +2776,7 @@ shutdown(struct e100_serial * info) if (info->port.tty) set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 0); local_irq_restore(flags); } @@ -3273,9 +3273,9 @@ set_serial_info(struct e100_serial *info, info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: - if (info->port.flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(&info->port)) change_speed(info); - } else + else retval = startup(info); return retval; } @@ -3628,7 +3628,7 @@ rs_close(struct tty_struct *tty, struct file * filp) e100_disable_rx(info); e100_disable_rx_irq(info); - if (info->port.flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(&info->port)) { /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially @@ -3787,8 +3787,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, e100_dtr(info, 1); local_irq_restore(flags); set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->port.flags & ASYNC_INITIALIZED)) { + if (tty_hung_up_p(filp) || !tty_port_initialized(&info->port)) { #ifdef SERIAL_DO_RESTART if (info->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9336067..0c48051 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -196,7 +196,7 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, struct tty_port *port = &state->port; int retval; - if (port->flags & ASYNC_INITIALIZED) + if (tty_port_initialized(port)) return 0; /* @@ -207,7 +207,7 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, retval = uart_port_startup(tty, state, init_hw); if (!retval) { - set_bit(ASYNCB_INITIALIZED, &port->flags); + tty_port_set_initialized(port, 1); clear_bit(TTY_IO_ERROR, &tty->flags); } else if (retval > 0) retval = 0; @@ -231,7 +231,9 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) if (tty) set_bit(TTY_IO_ERROR, &tty->flags); - if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (tty_port_initialized(port)) { + tty_port_set_initialized(port, 0); + /* * Turn off DTR and RTS early. */ @@ -886,7 +888,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, retval = 0; if (uport->type == PORT_UNKNOWN) goto exit; - if (port->flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(port)) { if (((old_flags ^ uport->flags) & UPF_SPD_MASK) || old_custom_divisor != uport->custom_divisor) { /* @@ -1390,7 +1392,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * At this point, we stop accepting input. To do this, we * disable the receive line status interrupts. */ - if (port->flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(port)) { spin_lock_irq(&uport->lock); uport->ops->stop_rx(uport); spin_unlock_irq(&uport->lock); @@ -2003,12 +2005,12 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) uport->suspended = 1; - if (port->flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(port)) { const struct uart_ops *ops = uport->ops; int tries; tty_port_set_suspended(port, 1); - clear_bit(ASYNCB_INITIALIZED, &port->flags); + tty_port_set_initialized(port, 0); spin_lock_irq(&uport->lock); ops->stop_tx(uport); @@ -2107,7 +2109,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) ops->set_mctrl(uport, uport->mctrl); ops->start_tx(uport); spin_unlock_irq(&uport->lock); - set_bit(ASYNCB_INITIALIZED, &port->flags); + tty_port_set_initialized(port, 1); } else { /* * Failed to resume - maybe hardware went away? @@ -2248,10 +2250,10 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) ret = 0; mutex_lock(&tport->mutex); /* - * We don't set ASYNCB_INITIALIZED as we only initialized the - * hw, e.g. state->xmit is still uninitialized. + * We don't set initialized as we only initialized the hw, + * e.g. state->xmit is still uninitialized. */ - if (!test_bit(ASYNCB_INITIALIZED, &tport->flags)) + if (!tty_port_initialized(tport)) ret = port->ops->poll_init(port); mutex_unlock(&tport->mutex); if (ret) diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index b67b54a..bc4bc1f 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -1749,13 +1749,13 @@ static irqreturn_t mgsl_interrupt(int dummy, void *dev_id) static int startup(struct mgsl_struct * info) { int retval = 0; - + if ( debug_level >= DEBUG_LEVEL_INFO ) printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name); - - if (info->port.flags & ASYNC_INITIALIZED) + + if (tty_port_initialized(&info->port)) return 0; - + if (!info->xmit_buf) { /* allocate a page of memory for a transmit buffer */ info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); @@ -1788,14 +1788,13 @@ static int startup(struct mgsl_struct * info) /* program hardware for current parameters */ mgsl_change_params(info); - + if (info->port.tty) clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->port.flags |= ASYNC_INITIALIZED; - + tty_port_set_initialized(&info->port, 1); + return 0; - } /* end of startup() */ /* shutdown() @@ -1808,8 +1807,8 @@ static int startup(struct mgsl_struct * info) static void shutdown(struct mgsl_struct * info) { unsigned long flags; - - if (!(info->port.flags & ASYNC_INITIALIZED)) + + if (!tty_port_initialized(&info->port)) return; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1853,13 +1852,12 @@ static void shutdown(struct mgsl_struct * info) spin_unlock_irqrestore(&info->irq_spinlock,flags); - mgsl_release_resources(info); - + mgsl_release_resources(info); + if (info->port.tty) set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; - + tty_port_set_initialized(&info->port, 0); } /* end of shutdown() */ static void mgsl_program_hw(struct mgsl_struct *info) @@ -3084,7 +3082,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) goto cleanup; mutex_lock(&info->port.mutex); - if (info->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&info->port)) mgsl_wait_until_sent(tty, info->timeout); mgsl_flush_buffer(tty); tty_ldisc_flush(tty); @@ -3122,15 +3120,15 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_wait_until_sent(%s) entry\n", __FILE__,__LINE__, info->device_name ); - + if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent")) return; - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) goto exit; - + orig_jiffies = jiffies; - + /* Set check interval to 1/5 of estimated time to * send a character, and make it at least 1. The check * interval should also be less than the timeout. @@ -3290,14 +3288,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, port->count--; spin_unlock_irqrestore(&info->irq_spinlock, flags); port->blocked_open++; - + while (1) { - if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags)) + if (C_BAUD(tty) && tty_port_initialized(port)) tty_port_raise_dtr_rts(port); - + set_current_state(TASK_INTERRUPTIBLE); - - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ + + if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { retval = (port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 333652a..82c98b8 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -726,7 +726,7 @@ static void close(struct tty_struct *tty, struct file *filp) goto cleanup; mutex_lock(&info->port.mutex); - if (info->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&info->port)) wait_until_sent(tty, info->timeout); flush_buffer(tty); tty_ldisc_flush(tty); @@ -893,7 +893,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) if (sanity_check(info, tty->name, "wait_until_sent")) return; DBGINFO(("%s wait_until_sent entry\n", info->device_name)); - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) goto exit; orig_jiffies = jiffies; @@ -2421,7 +2421,7 @@ static int startup(struct slgt_info *info) { DBGINFO(("%s startup\n", info->device_name)); - if (info->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&info->port)) return 0; if (!info->tx_buf) { @@ -2442,7 +2442,7 @@ static int startup(struct slgt_info *info) if (info->port.tty) clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->port.flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 1); return 0; } @@ -2454,7 +2454,7 @@ static void shutdown(struct slgt_info *info) { unsigned long flags; - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) return; DBGINFO(("%s shutdown\n", info->device_name)); @@ -2489,7 +2489,7 @@ static void shutdown(struct slgt_info *info) if (info->port.tty) set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 0); } static void program_hw(struct slgt_info *info) @@ -3287,12 +3287,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, port->blocked_open++; while (1) { - if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags)) + if (C_BAUD(tty) && tty_port_initialized(port)) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ + if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { retval = (port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 17bab5f..6dcfc20 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -812,7 +812,7 @@ static void close(struct tty_struct *tty, struct file *filp) goto cleanup; mutex_lock(&info->port.mutex); - if (info->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&info->port)) wait_until_sent(tty, info->timeout); flush_buffer(tty); @@ -1061,7 +1061,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) if (sanity_check(info, tty->name, "wait_until_sent")) return; - if (!test_bit(ASYNCB_INITIALIZED, &info->port.flags)) + if (!tty_port_initialized(&info->port)) goto exit; orig_jiffies = jiffies; @@ -2636,7 +2636,7 @@ static int startup(SLMP_INFO * info) if ( debug_level >= DEBUG_LEVEL_INFO ) printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name); - if (info->port.flags & ASYNC_INITIALIZED) + if (tty_port_initialized(&info->port)) return 0; if (!info->tx_buf) { @@ -2662,7 +2662,7 @@ static int startup(SLMP_INFO * info) if (info->port.tty) clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->port.flags |= ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 1); return 0; } @@ -2673,7 +2673,7 @@ static void shutdown(SLMP_INFO * info) { unsigned long flags; - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!tty_port_initialized(&info->port)) return; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2705,7 +2705,7 @@ static void shutdown(SLMP_INFO * info) if (info->port.tty) set_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; + tty_port_set_initialized(&info->port, 0); } static void program_hw(SLMP_INFO *info) @@ -3308,12 +3308,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, port->blocked_open++; while (1) { - if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags)) + if (C_BAUD(tty) && tty_port_initialized(port)) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ + if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { retval = (port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 130c8cf..c3f9d93 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -204,7 +204,8 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) if (port->console) goto out; - if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (tty_port_initialized(port)) { + tty_port_set_initialized(port, 0); /* * Drop DTR/RTS if HUPCL is set. This causes any attached * modem to hang up the line. @@ -393,13 +394,13 @@ int tty_port_block_til_ready(struct tty_port *port, while (1) { /* Indicate we are open */ - if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags)) + if (C_BAUD(tty) && tty_port_initialized(port)) tty_port_raise_dtr_rts(port); prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); /* Check for a hangup or uninitialised port. Return accordingly */ - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { + if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else @@ -480,7 +481,7 @@ int tty_port_close_start(struct tty_port *port, tty->closing = 1; - if (test_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (tty_port_initialized(port)) { /* Don't block on a stalled port, just pull the chain */ if (tty->flow_stopped) tty_driver_flush_buffer(tty); @@ -578,7 +579,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty, mutex_lock(&port->mutex); - if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (!tty_port_initialized(port)) { clear_bit(TTY_IO_ERROR, &tty->flags); if (port->ops->activate) { int retval = port->ops->activate(port, tty); @@ -587,7 +588,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty, return retval; } } - set_bit(ASYNCB_INITIALIZED, &port->flags); + tty_port_set_initialized(port, 1); } mutex_unlock(&port->mutex); return tty_port_block_til_ready(port, tty, filp); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index a6c4a1b..94a14f5 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1680,7 +1680,7 @@ static int acm_resume(struct usb_interface *intf) if (--acm->susp_count) goto out; - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { + if (tty_port_initialized(&acm->port)) { rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); for (;;) { @@ -1710,7 +1710,7 @@ static int acm_reset_resume(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) + if (tty_port_initialized(&acm->port)) tty_port_tty_hangup(&acm->port, false); return acm_resume(intf); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index a66b01b..8967715 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -127,7 +127,7 @@ static int usb_console_setup(struct console *co, char *options) info->port = port; ++port->port.count; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { + if (!tty_port_initialized(&port->port)) { if (serial->type->set_termios) { /* * allocate a fake tty so the driver can initialize @@ -168,7 +168,7 @@ static int usb_console_setup(struct console *co, char *options) tty_port_tty_set(&port->port, NULL); tty_kref_put(tty); } - set_bit(ASYNCB_INITIALIZED, &port->port.flags); + tty_port_set_initialized(&port->port, 1); } /* Now that any required fake tty operations are completed restore * the tty port count */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 54e170d..ae8c036 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -473,7 +473,7 @@ static bool usb_serial_generic_msr_changed(struct tty_struct *tty, * Use tty-port initialised flag to detect all hangups including the * one generated at USB-device disconnect. */ - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) return true; spin_lock_irqsave(&port->lock, flags); @@ -503,7 +503,7 @@ int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg) ret = wait_event_interruptible(port->port.delta_msr_wait, usb_serial_generic_msr_changed(tty, arg, &cnow)); - if (!ret && !test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!ret && !tty_port_initialized(&port->port)) ret = -EIO; return ret; @@ -606,7 +606,7 @@ int usb_serial_generic_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) continue; if (port->bulk_in_size) { diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index 31a8b47..3722d6c 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -503,7 +503,7 @@ static void mxuport_process_read_urb_demux_data(struct urb *urb) return; } - if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) { + if (tty_port_initialized(&demux_port->port)) { ch = data + HEADER_SIZE; mxuport_process_read_urb_data(demux_port, ch, rcv_len); } else { @@ -544,7 +544,7 @@ static void mxuport_process_read_urb_demux_event(struct urb *urb) } demux_port = serial->port[rcv_port]; - if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) { + if (tty_port_initialized(&demux_port->port)) { ch = data + HEADER_SIZE; rcv_event = get_unaligned_be16(data + 2); mxuport_process_read_urb_event(demux_port, ch, @@ -1339,7 +1339,7 @@ static int mxuport_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) continue; r = usb_serial_generic_write_start(port, GFP_NOIO); diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 07d1ecd..e1994e2 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -776,7 +776,7 @@ static void sierra_close(struct usb_serial_port *port) /* * Need to take susp_lock to make sure port is not already being - * resumed, but no need to hold it due to ASYNC_INITIALIZED. + * resumed, but no need to hold it due to initialized */ spin_lock_irq(&intfdata->susp_lock); if (--intfdata->open_ports == 0) @@ -1039,7 +1039,7 @@ static int sierra_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) continue; err = sierra_submit_delayed_urbs(port); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 46f1f13..3f253ae 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -254,7 +254,7 @@ static int serial_open(struct tty_struct *tty, struct file *filp) * * Shut down a USB serial port. Serialized against activate by the * tport mutex and kept to matching open/close pairs - * of calls by the ASYNCB_INITIALIZED flag. + * of calls by the initialized flag. * * Not called if tty is console. */ diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index be9cb61..3dfdfc8 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -464,7 +464,7 @@ void usb_wwan_close(struct usb_serial_port *port) /* * Need to take susp_lock to make sure port is not already being - * resumed, but no need to hold it due to ASYNC_INITIALIZED. + * resumed, but no need to hold it due to initialized */ spin_lock_irq(&intfdata->susp_lock); if (--intfdata->open_ports == 0) @@ -682,7 +682,7 @@ int usb_wwan_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) continue; portdata = usb_get_serial_port_data(port); diff --git a/include/linux/tty.h b/include/linux/tty.h index 7ac5add..bf1bcdb 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -610,6 +610,19 @@ static inline void tty_port_set_suspended(struct tty_port *port, bool val) clear_bit(TTY_PORT_SUSPENDED, &port->iflags); } +static inline bool tty_port_initialized(struct tty_port *port) +{ + return test_bit(TTY_PORT_INITIALIZED, &port->iflags); +} + +static inline void tty_port_set_initialized(struct tty_port *port, bool val) +{ + if (val) + set_bit(TTY_PORT_INITIALIZED, &port->iflags); + else + clear_bit(TTY_PORT_INITIALIZED, &port->iflags); +} + extern struct tty_struct *tty_port_tty_get(struct tty_port *port); extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); extern int tty_port_carrier_raised(struct tty_port *port); diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 5b7ce59..873c4b7 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -220,10 +220,11 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self) IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); /* Check if already open */ - if (test_and_set_bit(ASYNCB_INITIALIZED, &self->port.flags)) { + if (tty_port_initialized(&self->port)) { pr_debug("%s(), already open so break out!\n", __func__); return 0; } + tty_port_set_initialized(&self->port, 1); /* Register with IrCOMM */ irda_notify_init(¬ify); @@ -257,7 +258,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self) return 0; err: - clear_bit(ASYNCB_INITIALIZED, &self->port.flags); + tty_port_set_initialized(&self->port, 0); return ret; } @@ -318,13 +319,12 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, spin_unlock_irqrestore(&port->lock, flags); while (1) { - if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags)) + if (C_BAUD(tty) && tty_port_initialized(port)) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !test_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { retval = (port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; @@ -876,8 +876,9 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self) IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - if (!test_and_clear_bit(ASYNCB_INITIALIZED, &self->port.flags)) + if (!tty_port_initialized(&self->port)) return; + tty_port_set_initialized(&self->port, 0); ircomm_tty_detach_cable(self); @@ -1259,7 +1260,7 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) seq_printf(m, "%cASYNC_CHECK_CD", sep); sep = '|'; } - if (self->port.flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(&self->port)) { seq_printf(m, "%cASYNC_INITIALIZED", sep); sep = '|'; } diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index e24724d..d4fdf8f 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -324,7 +324,7 @@ static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self, check_and_exit: - if (self->flags & ASYNC_INITIALIZED) { + if (tty_port_initialized(self)) { if (((old_state.flags & ASYNC_SPD_MASK) != (self->flags & ASYNC_SPD_MASK)) || (old_driver.custom_divisor != driver->custom_divisor)) { -- cgit v1.1 From 03fe27675e498796f9e7c9b500d667000928bc1c Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:53:26 -0700 Subject: tty: mxser: Remove unused ASYNC_SHARE_IRQ flag ASYNC*_SHARE_IRQ is no longer used; remove. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 7e8c27b..98d2bd1 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -2392,7 +2392,6 @@ static int mxser_initbrd(struct mxser_board *brd, if (brd->chip_flag != MOXA_OTHER_UART) mxser_enable_must_enchance_mode(info->ioaddr); - info->port.flags = ASYNC_SHARE_IRQ; info->type = brd->uart_type; process_txrx_fifo(info); -- cgit v1.1 From 5c0517fefc92d636e409141ed75c29c3f1969107 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 17:53:27 -0700 Subject: tty: core: Undefine ASYNC_* flags superceded by TTY_PORT* flags Purposefully break out-of-tree driver compiles using kernel ASYNC_* bits which have been superceded by TTY_PORT* flags and their respective helper functions. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/tty_flags.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/uapi/linux/tty_flags.h b/include/uapi/linux/tty_flags.h index 8e1a436..66e4d8b 100644 --- a/include/uapi/linux/tty_flags.h +++ b/include/uapi/linux/tty_flags.h @@ -38,6 +38,7 @@ * WARNING: These flags are no longer used and have been superceded by the * TTY_PORT_ flags in the iflags field (and not userspace-visible) */ +#ifndef _KERNEL_ #define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ #define ASYNCB_SUSPENDED 30 /* Serial port is suspended */ #define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */ @@ -48,6 +49,7 @@ #define ASYNCB_SHARE_IRQ 24 /* for multifunction cards, no longer used */ #define ASYNCB_CONS_FLOW 23 /* flow control for console */ #define ASYNCB_FIRST_KERNEL 22 +#endif /* Masks */ #define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY) @@ -78,6 +80,7 @@ #define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) #define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) +#ifndef _KERNEL_ /* These flags are no longer used (and were always masked from userspace) */ #define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED) #define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE) @@ -88,5 +91,6 @@ #define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ) #define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW) #define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1)) +#endif #endif -- cgit v1.1 From 49c02304fe97f88ee65f92368fe3f473201a7976 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 18:56:32 -0700 Subject: serial: core: Expand port mutex section in uart_poll_init() Prepare uart_poll_init() to safely dereference uart port; expand the port mutex section to guarantee uart port remains valid until uart_poll_init() completes. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0c48051..53d8486 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2230,42 +2230,42 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) { struct uart_driver *drv = driver->driver_state; struct uart_state *state = drv->state + line; + struct tty_port *tport; struct uart_port *port; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; - int ret; + int ret = 0; - if (!state || !state->uart_port) + if (!state) return -1; + tport = &state->port; + mutex_lock(&tport->mutex); + port = state->uart_port; - if (!(port->ops->poll_get_char && port->ops->poll_put_char)) - return -1; + if (!(port->ops->poll_get_char && port->ops->poll_put_char)) { + ret = -1; + goto out; + } if (port->ops->poll_init) { - struct tty_port *tport = &state->port; - - ret = 0; - mutex_lock(&tport->mutex); /* * We don't set initialized as we only initialized the hw, * e.g. state->xmit is still uninitialized. */ if (!tty_port_initialized(tport)) ret = port->ops->poll_init(port); - mutex_unlock(&tport->mutex); - if (ret) - return ret; } - if (options) { + if (!ret && options) { uart_parse_options(options, &baud, &parity, &bits, &flow); - return uart_set_options(port, NULL, baud, parity, bits, flow); + ret = uart_set_options(port, NULL, baud, parity, bits, flow); } - - return 0; +out: + mutex_unlock(&tport->mutex); + return ret; } static int uart_poll_get_char(struct tty_driver *driver, int line) -- cgit v1.1 From 4047b37122d1be8dd8e8c504f6f596930b660188 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 18:56:33 -0700 Subject: serial: core: Prevent unsafe uart port access, part 1 uart_remove_one_port() may race with every serial core operation requiring a valid dereference of state->uart_port. In particular, uart_remove_one_port() may unlink the uart port concurrently with any serial core operation that may dereference same. Ensure safe dereference for those operations that already claim the port->mutex, and extend that guarantee for trivial cases, such as the ioctl handlers. Introduce the uart_port_check() helper which asserts port->mutex is held (only when lockdep is on). For ioctls, return -EIO as if the port has been hung up (since it has). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 157 ++++++++++++++++++++++++++------------- 1 file changed, 104 insertions(+), 53 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 53d8486..e605f03 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -64,6 +64,14 @@ static int uart_dcd_enabled(struct uart_port *uport) return !!(uport->status & UPSTAT_DCD_ENABLE); } +static inline struct uart_port *uart_port_check(struct uart_state *state) +{ +#ifdef CONFIG_LOCKDEP + WARN_ON(!lockdep_is_held(&state->port.mutex)); +#endif + return state->uart_port; +} + /* * This routine is used by the interrupt handler to schedule processing in * the software interrupt portion of the driver. @@ -134,7 +142,7 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) { - struct uart_port *uport = state->uart_port; + struct uart_port *uport = uart_port_check(state); unsigned long page; int retval = 0; @@ -222,7 +230,7 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, */ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) { - struct uart_port *uport = state->uart_port; + struct uart_port *uport = uart_port_check(state); struct tty_port *port = &state->port; /* @@ -443,7 +451,7 @@ EXPORT_SYMBOL(uart_get_divisor); static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios) { - struct uart_port *uport = state->uart_port; + struct uart_port *uport = uart_port_check(state); struct ktermios *termios; int hw_stopped; @@ -673,10 +681,11 @@ static void uart_unthrottle(struct tty_struct *tty) uart_send_xchar(tty, START_CHAR(tty)); } -static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo) +static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo) { struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; + struct uart_port *uport; + int ret = -ENODEV; memset(retinfo, 0, sizeof(*retinfo)); @@ -685,6 +694,10 @@ static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo) * occur as we go */ mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (!uport) + goto out; + retinfo->type = uport->type; retinfo->line = uport->line; retinfo->port = uport->iobase; @@ -703,7 +716,11 @@ static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo) retinfo->io_type = uport->iotype; retinfo->iomem_reg_shift = uport->regshift; retinfo->iomem_base = (void *)(unsigned long)uport->mapbase; + + ret = 0; +out: mutex_unlock(&port->mutex); + return ret; } static int uart_get_info_user(struct tty_port *port, @@ -711,7 +728,8 @@ static int uart_get_info_user(struct tty_port *port, { struct serial_struct tmp; - uart_get_info(port, &tmp); + if (uart_get_info(port, &tmp) < 0) + return -EIO; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; @@ -722,13 +740,16 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, struct uart_state *state, struct serial_struct *new_info) { - struct uart_port *uport = state->uart_port; + struct uart_port *uport = uart_port_check(state); unsigned long new_port; unsigned int change_irq, change_port, closing_wait; unsigned int old_custom_divisor, close_delay; upf_t old_flags, new_flags; int retval = 0; + if (!uport) + return -EIO; + new_port = new_info->port; if (HIGH_BITS_OFFSET) new_port += (unsigned long) new_info->port_high << HIGH_BITS_OFFSET; @@ -938,13 +959,11 @@ static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state, * @tty: tty associated with the UART * @state: UART being queried * @value: returned modem value - * - * Note: uart_ioctl protects us against hangups. */ static int uart_get_lsr_info(struct tty_struct *tty, struct uart_state *state, unsigned int __user *value) { - struct uart_port *uport = state->uart_port; + struct uart_port *uport = uart_port_check(state); unsigned int result; result = uport->ops->tx_empty(uport); @@ -967,18 +986,22 @@ static int uart_tiocmget(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; - struct uart_port *uport = state->uart_port; + struct uart_port *uport; int result = -EIO; mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (!uport) + goto out; + if (!tty_io_error(tty)) { result = uport->mctrl; spin_lock_irq(&uport->lock); result |= uport->ops->get_mctrl(uport); spin_unlock_irq(&uport->lock); } +out: mutex_unlock(&port->mutex); - return result; } @@ -986,15 +1009,20 @@ static int uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct uart_state *state = tty->driver_data; - struct uart_port *uport = state->uart_port; struct tty_port *port = &state->port; + struct uart_port *uport; int ret = -EIO; mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (!uport) + goto out; + if (!tty_io_error(tty)) { uart_update_mctrl(uport, set, clear); ret = 0; } +out: mutex_unlock(&port->mutex); return ret; } @@ -1003,21 +1031,26 @@ static int uart_break_ctl(struct tty_struct *tty, int break_state) { struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; - struct uart_port *uport = state->uart_port; + struct uart_port *uport; + int ret = -EIO; mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (!uport) + goto out; if (uport->type != PORT_UNKNOWN) uport->ops->break_ctl(uport, break_state); - + ret = 0; +out: mutex_unlock(&port->mutex); - return 0; + return ret; } static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) { - struct uart_port *uport = state->uart_port; struct tty_port *port = &state->port; + struct uart_port *uport; int flags, ret; if (!capable(CAP_SYS_ADMIN)) @@ -1031,6 +1064,12 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) if (mutex_lock_interruptible(&port->mutex)) return -ERESTARTSYS; + uport = uart_port_check(state); + if (!uport) { + ret = -EIO; + goto out; + } + ret = -EBUSY; if (tty_port_users(port) == 1) { uart_shutdown(tty, state); @@ -1054,6 +1093,7 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) ret = uart_startup(tty, state, 1); } +out: mutex_unlock(&port->mutex); return ret; } @@ -1202,11 +1242,11 @@ static int uart_set_rs485_config(struct uart_port *port, * Called via sys_ioctl. We can use spin_lock_irq() here. */ static int -uart_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) +uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; + struct uart_port *uport; void __user *uarg = (void __user *)arg; int ret = -ENOIOCTLCMD; @@ -1258,8 +1298,9 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, goto out; mutex_lock(&port->mutex); + uport = uart_port_check(state); - if (tty_io_error(tty)) { + if (!uport || tty_io_error(tty)) { ret = -EIO; goto out_up; } @@ -1275,19 +1316,17 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, break; case TIOCGRS485: - ret = uart_get_rs485_config(state->uart_port, uarg); + ret = uart_get_rs485_config(uport, uarg); break; case TIOCSRS485: - ret = uart_set_rs485_config(state->uart_port, uarg); + ret = uart_set_rs485_config(uport, uarg); break; - default: { - struct uart_port *uport = state->uart_port; + default: if (uport->ops->ioctl) ret = uport->ops->ioctl(uport, cmd, arg); break; } - } out_up: mutex_unlock(&port->mutex); out: @@ -1297,24 +1336,29 @@ out: static void uart_set_ldisc(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *uport = state->uart_port; + struct uart_port *uport; - if (uport->ops->set_ldisc) { - mutex_lock(&state->port.mutex); + mutex_lock(&state->port.mutex); + uport = uart_port_check(state); + if (uport && uport->ops->set_ldisc) uport->ops->set_ldisc(uport, &tty->termios); - mutex_unlock(&state->port.mutex); - } + mutex_unlock(&state->port.mutex); } static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct uart_state *state = tty->driver_data; - struct uart_port *uport = state->uart_port; + struct uart_port *uport; unsigned int cflag = tty->termios.c_cflag; unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK; bool sw_changed = false; + mutex_lock(&state->port.mutex); + uport = uart_port_check(state); + if (!uport) + goto out; + /* * Drivers doing software flow control also need to know * about changes to these input settings. @@ -1337,12 +1381,10 @@ static void uart_set_termios(struct tty_struct *tty, tty->termios.c_ispeed == old_termios->c_ispeed && ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 && !sw_changed) { - return; + goto out; } - mutex_lock(&state->port.mutex); uart_change_speed(tty, state, old_termios); - mutex_unlock(&state->port.mutex); /* reload cflag from termios; port driver may have overriden flags */ cflag = tty->termios.c_cflag; @@ -1356,6 +1398,8 @@ static void uart_set_termios(struct tty_struct *tty, mask |= TIOCM_RTS; uart_set_mctrl(uport, mask); } +out: + mutex_unlock(&state->port.mutex); } /* @@ -1522,7 +1566,7 @@ static void uart_hangup(struct tty_struct *tty) static void uart_port_shutdown(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; + struct uart_port *uport = uart_port_check(state); /* * clear delta_msr_wait queue to avoid mem leaks: we may free @@ -1585,6 +1629,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) int retval, line = tty->index; struct uart_state *state = drv->state + line; struct tty_port *port = &state->port; + struct uart_port *uport; pr_debug("uart_open(%d) called\n", line); @@ -1604,15 +1649,15 @@ static int uart_open(struct tty_struct *tty, struct file *filp) goto end; } - if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { + uport = uart_port_check(state); + if (!uport || uport->flags & UPF_DEAD) { retval = -ENXIO; goto err_unlock; } tty->driver_data = state; - state->uart_port->state = state; - state->port.low_latency = - (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; + uport->state = state; + port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; tty_port_tty_set(port, tty); /* @@ -1651,13 +1696,15 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) struct uart_state *state = drv->state + i; struct tty_port *port = &state->port; enum uart_pm_state pm_state; - struct uart_port *uport = state->uart_port; + struct uart_port *uport; char stat_buf[32]; unsigned int status; int mmio; + mutex_lock(&port->mutex); + uport = uart_port_check(state); if (!uport) - return; + goto out; mmio = uport->iotype >= UPIO_MEM; seq_printf(m, "%d: uart:%s %s%08llX irq:%d", @@ -1669,11 +1716,10 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) if (uport->type == PORT_UNKNOWN) { seq_putc(m, '\n'); - return; + goto out; } if (capable(CAP_SYS_ADMIN)) { - mutex_lock(&port->mutex); pm_state = state->pm_state; if (pm_state != UART_PM_STATE_ON) uart_change_pm(state, UART_PM_STATE_ON); @@ -1682,7 +1728,6 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) spin_unlock_irq(&uport->lock); if (pm_state != UART_PM_STATE_ON) uart_change_pm(state, pm_state); - mutex_unlock(&port->mutex); seq_printf(m, " tx:%d rx:%d", uport->icount.tx, uport->icount.rx); @@ -1720,6 +1765,8 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) seq_putc(m, '\n'); #undef STATBIT #undef INFOBIT +out: + mutex_unlock(&port->mutex); } static int uart_proc_show(struct seq_file *m, void *v) @@ -1956,10 +2003,10 @@ EXPORT_SYMBOL_GPL(uart_set_options); static void uart_change_pm(struct uart_state *state, enum uart_pm_state pm_state) { - struct uart_port *port = state->uart_port; + struct uart_port *port = uart_port_check(state); if (state->pm_state != pm_state) { - if (port->ops->pm) + if (port && port->ops->pm) port->ops->pm(port, pm_state, state->pm_state); state->pm_state = pm_state; } @@ -2244,8 +2291,8 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) tport = &state->port; mutex_lock(&tport->mutex); - port = state->uart_port; - if (!(port->ops->poll_get_char && port->ops->poll_put_char)) { + port = uart_port_check(state); + if (!port || !(port->ops->poll_get_char && port->ops->poll_put_char)) { ret = -1; goto out; } @@ -2713,15 +2760,12 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) { struct uart_state *state = drv->state + uport->line; struct tty_port *port = &state->port; + struct uart_port *uart_port; struct tty_struct *tty; int ret = 0; BUG_ON(in_interrupt()); - if (state->uart_port != uport) - dev_alert(uport->dev, "Removing wrong port: %p != %p\n", - state->uart_port, uport); - mutex_lock(&port_mutex); /* @@ -2729,7 +2773,12 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) * succeeding while we shut down the port. */ mutex_lock(&port->mutex); - if (!state->uart_port) { + uart_port = uart_port_check(state); + if (uart_port != uport) + dev_alert(uport->dev, "Removing wrong port: %p != %p\n", + uart_port, uport); + + if (!uart_port) { mutex_unlock(&port->mutex); ret = -EINVAL; goto out; @@ -2766,7 +2815,9 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) */ uport->type = PORT_UNKNOWN; + mutex_lock(&port->mutex); state->uart_port = NULL; + mutex_unlock(&port->mutex); out: mutex_unlock(&port_mutex); -- cgit v1.1 From 9ed19428a51d53477e2b79be3303fa08f8575749 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 18:56:34 -0700 Subject: serial: core: Prevent unsafe uart port access, part 2 For serial core operations not already excluded by holding port->mutex, use reference counting to protect deferencing the state->uart_port. Introduce helper functions, uart_port_ref() and uart_port_deref(), to wrap uart_port access, and helper macros, uart_port_lock() and uart_port_unlock(), to wrap combination uart_port access with uart port lock sections. Port removal in uart_remove_one_port() waits for reference count to drop to zero before detaching the uart port from struct uart_state. For functions only reading the tx circular buffer indexes (where the uart port lock is claimed to prevent concurrent users), a NULL uart port is simply ignored and the operation completes normally. For functions change the tx circular buffer indexes (where the uart port lock is claimed to prevent concurrent users), the operation is aborted if the uart port is NULL (ie., has been detached). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 171 +++++++++++++++++++++++++++++---------- include/linux/serial_core.h | 2 + 2 files changed, 130 insertions(+), 43 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index e605f03..1887f9c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -64,6 +64,35 @@ static int uart_dcd_enabled(struct uart_port *uport) return !!(uport->status & UPSTAT_DCD_ENABLE); } +static inline struct uart_port *uart_port_ref(struct uart_state *state) +{ + if (atomic_add_unless(&state->refcount, 1, 0)) + return state->uart_port; + return NULL; +} + +static inline void uart_port_deref(struct uart_port *uport) +{ + if (uport && atomic_dec_and_test(&uport->state->refcount)) + wake_up(&uport->state->remove_wait); +} + +#define uart_port_lock(state, flags) \ + ({ \ + struct uart_port *__uport = uart_port_ref(state); \ + if (__uport) \ + spin_lock_irqsave(&__uport->lock, flags); \ + __uport; \ + }) + +#define uart_port_unlock(uport, flags) \ + ({ \ + struct uart_port *__uport = uport; \ + if (__uport) \ + spin_unlock_irqrestore(&__uport->lock, flags); \ + uart_port_deref(__uport); \ + }) + static inline struct uart_port *uart_port_check(struct uart_state *state) { #ifdef CONFIG_LOCKDEP @@ -90,12 +119,13 @@ void uart_write_wakeup(struct uart_port *port) static void uart_stop(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - port->ops->stop_tx(port); - spin_unlock_irqrestore(&port->lock, flags); + port = uart_port_lock(state, flags); + if (port) + port->ops->stop_tx(port); + uart_port_unlock(port, flags); } static void __uart_start(struct tty_struct *tty) @@ -103,19 +133,19 @@ static void __uart_start(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - if (!uart_tx_stopped(port)) + if (port && !uart_tx_stopped(port)) port->ops->start_tx(port); } static void uart_start(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + port = uart_port_lock(state, flags); __uart_start(tty); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock(port, flags); } static void @@ -496,7 +526,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, static int uart_put_char(struct tty_struct *tty, unsigned char c) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port; struct circ_buf *circ; unsigned long flags; int ret = 0; @@ -505,13 +535,13 @@ static int uart_put_char(struct tty_struct *tty, unsigned char c) if (!circ->buf) return 0; - spin_lock_irqsave(&port->lock, flags); - if (uart_circ_chars_free(circ) != 0) { + port = uart_port_lock(state, flags); + if (port && uart_circ_chars_free(circ) != 0) { circ->buf[circ->head] = c; circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); ret = 1; } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock(port, flags); return ret; } @@ -538,14 +568,12 @@ static int uart_write(struct tty_struct *tty, return -EL3HLT; } - port = state->uart_port; circ = &state->xmit; - if (!circ->buf) return 0; - spin_lock_irqsave(&port->lock, flags); - while (1) { + port = uart_port_lock(state, flags); + while (port) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); if (count < c) c = count; @@ -559,32 +587,33 @@ static int uart_write(struct tty_struct *tty, } __uart_start(tty); - spin_unlock_irqrestore(&port->lock, flags); - + uart_port_unlock(port, flags); return ret; } static int uart_write_room(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; + struct uart_port *port; unsigned long flags; int ret; - spin_lock_irqsave(&state->uart_port->lock, flags); + port = uart_port_lock(state, flags); ret = uart_circ_chars_free(&state->xmit); - spin_unlock_irqrestore(&state->uart_port->lock, flags); + uart_port_unlock(port, flags); return ret; } static int uart_chars_in_buffer(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; + struct uart_port *port; unsigned long flags; int ret; - spin_lock_irqsave(&state->uart_port->lock, flags); + port = uart_port_lock(state, flags); ret = uart_circ_chars_pending(&state->xmit); - spin_unlock_irqrestore(&state->uart_port->lock, flags); + uart_port_unlock(port, flags); return ret; } @@ -603,14 +632,15 @@ static void uart_flush_buffer(struct tty_struct *tty) return; } - port = state->uart_port; pr_debug("uart_flush_buffer(%d) called\n", tty->index); - spin_lock_irqsave(&port->lock, flags); + port = uart_port_lock(state, flags); + if (!port) + return; uart_circ_clear(&state->xmit); if (port->ops->flush_buffer) port->ops->flush_buffer(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock(port, flags); tty_wakeup(tty); } @@ -621,9 +651,13 @@ static void uart_flush_buffer(struct tty_struct *tty) static void uart_send_xchar(struct tty_struct *tty, char ch) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port; unsigned long flags; + port = uart_port_ref(state); + if (!port) + return; + if (port->ops->send_xchar) port->ops->send_xchar(port, ch); else { @@ -633,14 +667,19 @@ static void uart_send_xchar(struct tty_struct *tty, char ch) port->ops->start_tx(port); spin_unlock_irqrestore(&port->lock, flags); } + uart_port_deref(port); } static void uart_throttle(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port; upstat_t mask = 0; + port = uart_port_ref(state); + if (!port) + return; + if (I_IXOFF(tty)) mask |= UPSTAT_AUTOXOFF; if (C_CRTSCTS(tty)) @@ -656,14 +695,20 @@ static void uart_throttle(struct tty_struct *tty) if (mask & UPSTAT_AUTOXOFF) uart_send_xchar(tty, STOP_CHAR(tty)); + + uart_port_deref(port); } static void uart_unthrottle(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port; upstat_t mask = 0; + port = uart_port_ref(state); + if (!port) + return; + if (I_IXOFF(tty)) mask |= UPSTAT_AUTOXOFF; if (C_CRTSCTS(tty)) @@ -679,6 +724,8 @@ static void uart_unthrottle(struct tty_struct *tty) if (mask & UPSTAT_AUTOXOFF) uart_send_xchar(tty, START_CHAR(tty)); + + uart_port_deref(port); } static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo) @@ -1116,10 +1163,9 @@ static void uart_enable_ms(struct uart_port *uport) * FIXME: This wants extracting into a common all driver implementation * of TIOCMWAIT using tty_port. */ -static int -uart_wait_modem_status(struct uart_state *state, unsigned long arg) +static int uart_wait_modem_status(struct uart_state *state, unsigned long arg) { - struct uart_port *uport = state->uart_port; + struct uart_port *uport; struct tty_port *port = &state->port; DECLARE_WAITQUEUE(wait, current); struct uart_icount cprev, cnow; @@ -1128,6 +1174,9 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) /* * note the counters on entry */ + uport = uart_port_ref(state); + if (!uport) + return -EIO; spin_lock_irq(&uport->lock); memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); uart_enable_ms(uport); @@ -1161,6 +1210,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) } __set_current_state(TASK_RUNNING); remove_wait_queue(&port->delta_msr_wait, &wait); + uart_port_deref(uport); return ret; } @@ -1176,11 +1226,15 @@ static int uart_get_icount(struct tty_struct *tty, { struct uart_state *state = tty->driver_data; struct uart_icount cnow; - struct uart_port *uport = state->uart_port; + struct uart_port *uport; + uport = uart_port_ref(state); + if (!uport) + return -EIO; spin_lock_irq(&uport->lock); memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); spin_unlock_irq(&uport->lock); + uart_port_deref(uport); icount->cts = cnow.cts; icount->dsr = cnow.dsr; @@ -1481,11 +1535,14 @@ static void uart_close(struct tty_struct *tty, struct file *filp) static void uart_wait_until_sent(struct tty_struct *tty, int timeout) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port; unsigned long char_time, expire; - if (port->type == PORT_UNKNOWN || port->fifosize == 0) + port = uart_port_ref(state); + if (!port || port->type == PORT_UNKNOWN || port->fifosize == 0) { + uart_port_deref(port); return; + } /* * Set the check interval to be 1/5 of the estimated time to @@ -1531,6 +1588,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) if (time_after(jiffies, expire)) break; } + uart_port_deref(port); } /* @@ -1591,12 +1649,23 @@ static void uart_port_shutdown(struct tty_port *port) static int uart_carrier_raised(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; + struct uart_port *uport; int mctrl; + + uport = uart_port_ref(state); + /* + * Should never observe uport == NULL since checks for hangup should + * abort the tty_port_block_til_ready() loop before checking for carrier + * raised -- but report carrier raised if it does anyway so open will + * continue and not sleep + */ + if (WARN_ON(!uport)) + return 1; spin_lock_irq(&uport->lock); uart_enable_ms(uport); mctrl = uport->ops->get_mctrl(uport); spin_unlock_irq(&uport->lock); + uart_port_deref(uport); if (mctrl & TIOCM_CAR) return 1; return 0; @@ -1605,12 +1674,18 @@ static int uart_carrier_raised(struct tty_port *port) static void uart_dtr_rts(struct tty_port *port, int onoff) { struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; + struct uart_port *uport; + + uport = uart_port_ref(state); + if (!uport) + return; if (onoff) uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); else uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); + + uart_port_deref(uport); } /* @@ -2320,12 +2395,15 @@ static int uart_poll_get_char(struct tty_driver *driver, int line) struct uart_driver *drv = driver->driver_state; struct uart_state *state = drv->state + line; struct uart_port *port; + int ret = -1; - if (!state || !state->uart_port) - return -1; - - port = state->uart_port; - return port->ops->poll_get_char(port); + if (state) { + port = uart_port_ref(state); + if (port) + ret = port->ops->poll_get_char(port); + uart_port_deref(port); + } + return ret; } static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) @@ -2334,14 +2412,17 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) struct uart_state *state = drv->state + line; struct uart_port *port; - if (!state || !state->uart_port) + if (!state) return; - port = state->uart_port; + port = uart_port_ref(state); + if (!port) + return; if (ch == '\n') port->ops->poll_put_char(port, '\r'); port->ops->poll_put_char(port, ch); + uart_port_deref(port); } #endif @@ -2688,6 +2769,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) } /* Link the port to the driver state table and vice versa */ + atomic_set(&state->refcount, 1); + init_waitqueue_head(&state->remove_wait); state->uart_port = uport; uport->state = state; @@ -2816,6 +2899,8 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) uport->type = PORT_UNKNOWN; mutex_lock(&port->mutex); + WARN_ON(atomic_dec_return(&state->refcount) < 0); + wait_event(state->remove_wait, !atomic_read(&state->refcount)); state->uart_port = NULL; mutex_unlock(&port->mutex); out: diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index cbfcf38..fd4ad4d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -281,6 +281,8 @@ struct uart_state { enum uart_pm_state pm_state; struct circ_buf xmit; + atomic_t refcount; + wait_queue_head_t remove_wait; struct uart_port *uart_port; }; -- cgit v1.1 From af224ca2df297440448b9d407d21b50982c6d532 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 18:56:35 -0700 Subject: serial: core: Prevent unsafe uart port access, part 3 For tty operations which may expect uart port to have been removed but still have other necessary work to accomplish, check for NULL uart port; specifically uart_close(), uart_hangup() and sub-functions (uart_shutdown() and uart_port_shutdown()). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 1887f9c..d529b5c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -257,6 +257,8 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. Calls to * uart_shutdown are serialised by the per-port semaphore. + * + * uport == NULL if uart_port has already been removed */ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) { @@ -275,7 +277,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Turn off DTR and RTS early. */ - if (uart_console(uport) && tty) + if (uport && uart_console(uport) && tty) uport->cons->cflag = tty->termios.c_cflag; if (!tty || C_HUPCL(tty)) @@ -1460,7 +1462,6 @@ out: * Calls to uart_close() are serialised via the tty_lock in * drivers/tty/tty_io.c:tty_release() * drivers/tty/tty_io.c:do_tty_hangup() - * This runs from a workqueue and can sleep for a _short_ time only. */ static void uart_close(struct tty_struct *tty, struct file *filp) { @@ -1479,18 +1480,21 @@ static void uart_close(struct tty_struct *tty, struct file *filp) return; } - uport = state->uart_port; port = &state->port; pr_debug("uart_close(%d) called\n", tty->index); - if (!port->count || tty_port_close_start(port, tty, filp) == 0) + if (tty_port_close_start(port, tty, filp) == 0) return; + mutex_lock(&port->mutex); + uport = uart_port_check(state); + /* * At this point, we stop accepting input. To do this, we * disable the receive line status interrupts. */ - if (tty_port_initialized(port)) { + if (tty_port_initialized(port) && + !WARN(!uport, "detached port still initialized!\n")) { spin_lock_irq(&uport->lock); uport->ops->stop_rx(uport); spin_unlock_irq(&uport->lock); @@ -1502,7 +1506,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_wait_until_sent(tty, uport->timeout); } - mutex_lock(&port->mutex); uart_shutdown(tty, state); tty_port_tty_set(port, NULL); @@ -1513,7 +1516,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) if (port->close_delay) msleep_interruptible(jiffies_to_msecs(port->close_delay)); spin_lock_irq(&port->lock); - } else if (!uart_console(uport)) { + } else if (uport && !uart_console(uport)) { spin_unlock_irq(&port->lock); uart_change_pm(state, UART_PM_STATE_OFF); spin_lock_irq(&port->lock); @@ -1600,11 +1603,15 @@ static void uart_hangup(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; + struct uart_port *uport; unsigned long flags; pr_debug("uart_hangup(%d)\n", tty->index); mutex_lock(&port->mutex); + uport = uart_port_check(state); + WARN(!uport, "hangup of detached port!\n"); + if (tty_port_active(port)) { uart_flush_buffer(tty); uart_shutdown(tty, state); @@ -1613,7 +1620,7 @@ static void uart_hangup(struct tty_struct *tty) spin_unlock_irqrestore(&port->lock, flags); tty_port_set_active(port, 0); tty_port_tty_set(port, NULL); - if (!uart_console(state->uart_port)) + if (uport && !uart_console(uport)) uart_change_pm(state, UART_PM_STATE_OFF); wake_up_interruptible(&port->open_wait); wake_up_interruptible(&port->delta_msr_wait); @@ -1621,6 +1628,7 @@ static void uart_hangup(struct tty_struct *tty) mutex_unlock(&port->mutex); } +/* uport == NULL if uart_port has already been removed */ static void uart_port_shutdown(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); @@ -1638,12 +1646,14 @@ static void uart_port_shutdown(struct tty_port *port) /* * Free the IRQ and disable the port. */ - uport->ops->shutdown(uport); + if (uport) + uport->ops->shutdown(uport); /* * Ensure that the IRQ handler isn't running on another CPU. */ - synchronize_irq(uport->irq); + if (uport) + synchronize_irq(uport->irq); } static int uart_carrier_raised(struct tty_port *port) -- cgit v1.1 From 0f0380b6177ab628b9e7c5a566dcdb3889e38dcb Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 20:36:38 -0700 Subject: tty: Remove unused TTY_NUMBER() macro TTY_NUMBER() has been unused since v2.5.71; removed by "[PATCH] callout removal: callout is gone". Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 320dc4d..3cdd63b 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -230,9 +230,6 @@ static void tty_del_file(struct file *file) tty_free_file(file); } - -#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) - /** * tty_name - return tty naming * @tty: tty structure -- cgit v1.1 From 25f3ecc28b431d6befcea0a4bafe8fe74c5a3988 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 20:36:39 -0700 Subject: tty: Remove stale parameter comment noctty was removed as a parameter by commit 11e1d4aa4da ("tty: Consolidate noctty check in tty_open()"). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 3cdd63b..50979be 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1960,7 +1960,6 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) * tty_lookup_driver - lookup a tty driver for a given device file * @device: device number * @filp: file pointer to tty - * @noctty: set if the device should not become a controlling tty * @index: index for the device in the @return driver * @return: driver for this inode (with increased refcount) * -- cgit v1.1 From 79c9473f115f99906b6ae443708b8ece480e2e88 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 7 Mar 2016 02:46:40 +0000 Subject: tty: msm_serial: remove static clk rate setting in probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue with setting up a fixed clock rate at probe is that it would overwrite the console rate set by the bootloader for its console device. This would result in serial out corruption or missing log when we system is booted with earlycon. This is not a issue if we boot system without earlycon. This setup is at least not required with the mainline driver, this code used to be required because the clk_enable() call would fail if clk_set_rate() wasn't called first. Originally the issue was noticed on DB410c which is based on APQ8016 chipset. Without this patch the console log with earlycon would look like: ... [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=64, nr_cpu_ids=1 [ 0.000000] NR_IRQS:64 nr_irqs:64 0 ����+HH��0.699378] console [ttyMSM0] enabled [ 0.699378] console [ttyMSM0] enabled [ 0.702003] bootconsole [uart0] disabled [ 0.702003] bootconsole [uart0] disabled ... with this patch I can see all the skipped lines on the console Reviewed-by: Stephen Boyd Signed-off-by: Srinivas Kandagatla Acked-by: Andy Gross Tested-by: Pramod Gurav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 96d3ce8..074c797 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1577,8 +1577,6 @@ static int msm_serial_probe(struct platform_device *pdev) msm_port->pclk = devm_clk_get(&pdev->dev, "iface"); if (IS_ERR(msm_port->pclk)) return PTR_ERR(msm_port->pclk); - - clk_set_rate(msm_port->clk, 1843200); } port->uartclk = clk_get_rate(msm_port->clk); -- cgit v1.1 From 736d553886a72274e58ff8a0e8a2899978042b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 6 Mar 2016 12:21:24 +0100 Subject: tty: serial: meson: Implement earlycon support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split off the bulk of the existing meson_serial_console_write() implementation into meson_serial_port_write() for implementing meson_serial_early_console_write(). Use "meson" as the earlycon driver name, courtesy of Nicolas. Signed-off-by: Nicolas Saenz Julienne Acked-by: Carlo Caione Signed-off-by: Andreas Färber Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 6 ++++++ drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/meson_uart.c | 42 ++++++++++++++++++++++++++++++------- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 0b3de80..36e1c7b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1039,6 +1039,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. the driver will use only 32-bit accessors to read/write the device registers. + meson, + Start an early, polled-mode console on a meson serial + port at the specified address. The serial port must + already be setup and configured. Options are not yet + supported. + msm_serial, Start an early, polled-mode console on an msm serial port at the specified address. The serial port diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 13d4ed6..aa86994 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -213,6 +213,7 @@ config SERIAL_MESON_CONSOLE bool "Support for console on meson" depends on SERIAL_MESON=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Say Y here if you wish to use a Amlogic MesonX UART as the system console (the system console is the device which diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 024445a..6aea0f4 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -481,18 +481,13 @@ static void meson_console_putchar(struct uart_port *port, int ch) writel(ch, port->membase + AML_UART_WFIFO); } -static void meson_serial_console_write(struct console *co, const char *s, - u_int count) +static void meson_serial_port_write(struct uart_port *port, const char *s, + u_int count) { - struct uart_port *port; unsigned long flags; int locked; u32 val, tmp; - port = meson_ports[co->index]; - if (!port) - return; - local_irq_save(flags); if (port->sysrq) { locked = 0; @@ -516,6 +511,18 @@ static void meson_serial_console_write(struct console *co, const char *s, local_irq_restore(flags); } +static void meson_serial_console_write(struct console *co, const char *s, + u_int count) +{ + struct uart_port *port; + + port = meson_ports[co->index]; + if (!port) + return; + + meson_serial_port_write(port, s, count); +} + static int meson_serial_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -554,6 +561,27 @@ static int __init meson_serial_console_init(void) } console_initcall(meson_serial_console_init); +static void meson_serial_early_console_write(struct console *co, + const char *s, + u_int count) +{ + struct earlycon_device *dev = co->data; + + meson_serial_port_write(&dev->port, s, count); +} + +static int __init +meson_serial_early_console_setup(struct earlycon_device *device, const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = meson_serial_early_console_write; + return 0; +} +OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart", + meson_serial_early_console_setup); + #define MESON_SERIAL_CONSOLE (&meson_serial_console) #else #define MESON_SERIAL_CONSOLE NULL -- cgit v1.1 From e31efceed2bf4a0a911bfe53d84098bec7085abe Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 6 Mar 2016 12:20:12 +0900 Subject: serial: mvebu-uart: fix platform_no_drv_owner.cocci warnings No need to set .owner here. The core will do it. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Wilson Ding Signed-off-by: Fengguang Wu Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 0ff2781..81008a9 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -615,7 +615,6 @@ static struct platform_driver mvebu_uart_platform_driver = { .probe = mvebu_uart_probe, .remove = mvebu_uart_remove, .driver = { - .owner = THIS_MODULE, .name = "mvebu-uart", .of_match_table = of_match_ptr(mvebu_uart_of_match), }, -- cgit v1.1 From 89ebc27427695bfc1e769f1dd99bd243d332ac7a Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 13 Mar 2016 19:48:52 -0400 Subject: drivers/tty: make serial/mvebu-uart.c explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/tty/serial/Kconfig:config SERIAL_MVEBU_UART drivers/tty/serial/Kconfig: bool "Marvell EBU serial port support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since the code wasn't using module_init to begin with, the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Cc: Wilson Ding Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 81008a9..ce362bd 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -1,5 +1,7 @@ /* * *************************************************************************** +* Marvell Armada-3700 Serial Driver +* Author: Wilson Ding * Copyright (C) 2015 Marvell International Ltd. * *************************************************************************** * This program is free software: you can redistribute it and/or modify it @@ -23,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -594,29 +595,18 @@ static int mvebu_uart_probe(struct platform_device *pdev) return 0; } -static int mvebu_uart_remove(struct platform_device *pdev) -{ - struct mvebu_uart_data *data = platform_get_drvdata(pdev); - - uart_remove_one_port(&mvebu_uart_driver, data->port); - data->port->private_data = NULL; - data->port->mapbase = 0; - return 0; -} - /* Match table for of_platform binding */ static const struct of_device_id mvebu_uart_of_match[] = { { .compatible = "marvell,armada-3700-uart", }, {} }; -MODULE_DEVICE_TABLE(of, mvebu_uart_of_match); static struct platform_driver mvebu_uart_platform_driver = { .probe = mvebu_uart_probe, - .remove = mvebu_uart_remove, .driver = { .name = "mvebu-uart", .of_match_table = of_match_ptr(mvebu_uart_of_match), + .suppress_bind_attrs = true, }, }; @@ -634,16 +624,4 @@ static int __init mvebu_uart_init(void) return ret; } - -static void __exit mvebu_uart_exit(void) -{ - platform_driver_unregister(&mvebu_uart_platform_driver); - uart_unregister_driver(&mvebu_uart_driver); -} - arch_initcall(mvebu_uart_init); -module_exit(mvebu_uart_exit); - -MODULE_AUTHOR("Wilson Ding "); -MODULE_DESCRIPTION("Marvell Armada-3700 Serial Driver"); -MODULE_LICENSE("GPL"); -- cgit v1.1 From 3d23b4c364e6fca720bf68655248c16c498e36f3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 18 Mar 2016 13:45:51 +0100 Subject: serial: Make SERIAL_MVEBU_UART depend on ARCH_MVEBU Enabling support for the UART on Marvell EBU SoCs only make sense when compiling for Marvell EBU SoCs, unless compile-testing. Signed-off-by: Geert Uytterhoeven Acked-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index aa86994..2857bd6 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1605,6 +1605,7 @@ config SERIAL_STM32_CONSOLE config SERIAL_MVEBU_UART bool "Marvell EBU serial port support" + depends on ARCH_MVEBU || COMPILE_TEST select SERIAL_CORE help This driver is for Marvell EBU SoC's UART. If you have a machine -- cgit v1.1 From 7d1cadca957d3c586fe71054ed843565013236d9 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 29 Feb 2016 14:34:10 +0200 Subject: serial: imx: support RS-485 Rx disable on Tx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some RS-232 to RS-485 transceivers require Rx to be disabled on Tx to avoid echo of Tx data into the Rx buffer. Specifically, the XR3160E RS-232/RS-485/RS-422 transceiver behaves this way. This commit disables Rx on active Tx when SER_RS485_ENABLED is active and SER_RS485_RX_DURING_TX is disabled. Note that this is a change in behavior of the driver. Until now SER_RS485_RX_DURING_TX was enabled unconditionally even when disabled in the TIOCSRS485 ioctl serial_rs485 flags field. Cc: Uwe Kleine-König Signed-off-by: Baruch Siach Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 231e7d5..66cc3d1 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -361,6 +361,7 @@ static void imx_stop_tx(struct uart_port *port) imx_port_rts_inactive(sport, &temp); else imx_port_rts_active(sport, &temp); + temp |= UCR2_RXEN; writel(temp, port->membase + UCR2); temp = readl(port->membase + UCR4); @@ -568,6 +569,8 @@ static void imx_start_tx(struct uart_port *port) imx_port_rts_inactive(sport, &temp); else imx_port_rts_active(sport, &temp); + if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) + temp &= ~UCR2_RXEN; writel(temp, port->membase + UCR2); /* enable transmitter and shifter empty irq */ @@ -1610,19 +1613,17 @@ static int imx_rs485_config(struct uart_port *port, struct serial_rs485 *rs485conf) { struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; /* unimplemented */ rs485conf->delay_rts_before_send = 0; rs485conf->delay_rts_after_send = 0; - rs485conf->flags |= SER_RS485_RX_DURING_TX; /* RTS is required to control the transmitter */ if (!sport->have_rtscts) rs485conf->flags &= ~SER_RS485_ENABLED; if (rs485conf->flags & SER_RS485_ENABLED) { - unsigned long temp; - /* disable transmitter */ temp = readl(sport->port.membase + UCR2); if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) @@ -1632,6 +1633,14 @@ static int imx_rs485_config(struct uart_port *port, writel(temp, sport->port.membase + UCR2); } + /* Make sure Rx is enabled in case Tx is active with Rx disabled */ + if (!(rs485conf->flags & SER_RS485_ENABLED) || + rs485conf->flags & SER_RS485_RX_DURING_TX) { + temp = readl(sport->port.membase + UCR2); + temp |= UCR2_RXEN; + writel(temp, sport->port.membase + UCR2); + } + port->rs485 = *rs485conf; return 0; -- cgit v1.1 From 03e970bba4376f7de9d1c97f2c830fac0b4e5a08 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 14 Apr 2016 12:01:32 +0200 Subject: serial: mctrl_gpio: Grammar s/lines GPIOs/line GPIOs/, /sets/set/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_mctrl_gpio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index 9716db2..bcfad5d 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -62,7 +62,7 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx); /* - * Request and set direction of modem control lines GPIOs and sets up irq + * Request and set direction of modem control line GPIOs and set up irq * handling. * devm_* functions are used, so there's no need to call mctrl_gpio_free(). * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on @@ -71,7 +71,7 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx); /* - * Request and set direction of modem control lines GPIOs. + * Request and set direction of modem control line GPIOs. * devm_* functions are used, so there's no need to call mctrl_gpio_free(). * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on * allocation error. -- cgit v1.1 From e69ef01ff0580b106e5b93a09c0c3fcd01fdb84f Mon Sep 17 00:00:00 2001 From: Wills Wang Date: Sat, 5 Mar 2016 22:09:05 +0800 Subject: sc16is7xx: remove useless "uart_handle_cts_change" SC16is7xx has feature for auto hardware flow control using RTS/CTS, so we don't need "uart_handle_cts_change" to invoke "start_tx/stop_tx" for flow control. In addition, for software CTS, interrupt "SC16IS7XX_IIR_CTSRTS_SRC" just report the nCTS change of state from active(low) to inactive(high), driver don't know when the state of nCTS change from incactive to active, so can't resume the transmission when a peer device is again ready and re-assert nRTS signal. Signed-off-by: Wills Wang Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 025a426..917504a 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -666,7 +666,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) struct uart_port *port = &s->p[portno].port; do { - unsigned int iir, msr, rxlen; + unsigned int iir, rxlen; iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); if (iir & SC16IS7XX_IIR_NO_INT_BIT) @@ -683,12 +683,6 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) if (rxlen) sc16is7xx_handle_rx(port, rxlen, iir); break; - - case SC16IS7XX_IIR_CTSRTS_SRC: - msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG); - uart_handle_cts_change(port, - !!(msr & SC16IS7XX_MSR_DCTS_BIT)); - break; case SC16IS7XX_IIR_THRI_SRC: sc16is7xx_handle_tx(port); break; @@ -1014,9 +1008,8 @@ static int sc16is7xx_startup(struct uart_port *port) SC16IS7XX_EFCR_TXDISABLE_BIT, 0); - /* Enable RX, TX, CTS change interrupts */ - val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT | - SC16IS7XX_IER_CTSI_BIT; + /* Enable RX, TX interrupts */ + val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT; sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); return 0; -- cgit v1.1 From 254da0d753fbebb6f4604bc266acd5f4c84bf6f5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 16 Mar 2016 14:05:52 +0100 Subject: serial: mxs-auart: add Alphascale ASM9260 support Alphascale ASM9260 uart IP has some common registers with Freescale STMP37XX. This patch provide changes which allow to reuse mxs-auart.c code for ASM9260. Reviewed-by: Peter Hurley Signed-off-by: Oleksij Rempel Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/fsl-mxs-auart.txt | 14 +- drivers/tty/serial/Kconfig | 5 +- drivers/tty/serial/mxs-auart.c | 641 +++++++++++++++++---- 3 files changed, 531 insertions(+), 129 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt index 7c408c8..81e35cd 100644 --- a/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt @@ -1,8 +1,10 @@ * Freescale MXS Application UART (AUART) -Required properties: -- compatible : Should be "fsl,-auart". The supported SoCs include - imx23 and imx28. +Required properties for all SoCs: +- compatible : Should be one of fallowing variants: + "fsl,imx23-auart" - Freescale i.MX23 + "fsl,imx28-auart" - Freescale i.MX28 + "alphascale,asm9260-auart" - Alphascale ASM9260 - reg : Address and length of the register set for the device - interrupts : Should contain the auart interrupt numbers - dmas: DMA specifier, consisting of a phandle to DMA controller node @@ -10,6 +12,12 @@ Required properties: Refer to dma.txt and fsl-mxs-dma.txt for details. - dma-names: "rx" for RX channel, "tx" for TX channel. +Required properties for "alphascale,asm9260-auart": +- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt +- clock-names : should be set to + "mod" - source for tick counter. + "ahb" - ahb gate. + Optional properties: - fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines for hardware flow control, diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 2857bd6..9af489b 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1384,11 +1384,12 @@ config SERIAL_PCH_UART_CONSOLE config SERIAL_MXS_AUART tristate "MXS AUART support" depends on HAS_DMA - depends on ARCH_MXS || COMPILE_TEST + depends on ARCH_MXS || MACH_ASM9260 || COMPILE_TEST select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB help - This driver supports the MXS Application UART (AUART) port. + This driver supports the MXS and Alphascale ASM9260 Application + UART (AUART) port. config SERIAL_MXS_AUART_CONSOLE bool "MXS AUART console support" diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index cd0414b..68a6e95 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1,17 +1,18 @@ /* - * Freescale STMP37XX/STMP378X Application UART driver + * Application UART driver for: + * Freescale STMP37XX/STMP378X + * Alphascale ASM9260 * * Author: dmitry pervushin * + * Copyright 2014 Oleksij Rempel + * Provide Alphascale ASM9260 support. * Copyright 2008-2010 Freescale Semiconductor, Inc. * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. * * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #if defined(CONFIG_SERIAL_MXS_AUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -51,30 +52,16 @@ #define MXS_AUART_PORTS 5 #define MXS_AUART_FIFO_SIZE 16 +#define SET_REG 0x4 +#define CLR_REG 0x8 +#define TOG_REG 0xc + #define AUART_CTRL0 0x00000000 -#define AUART_CTRL0_SET 0x00000004 -#define AUART_CTRL0_CLR 0x00000008 -#define AUART_CTRL0_TOG 0x0000000c #define AUART_CTRL1 0x00000010 -#define AUART_CTRL1_SET 0x00000014 -#define AUART_CTRL1_CLR 0x00000018 -#define AUART_CTRL1_TOG 0x0000001c #define AUART_CTRL2 0x00000020 -#define AUART_CTRL2_SET 0x00000024 -#define AUART_CTRL2_CLR 0x00000028 -#define AUART_CTRL2_TOG 0x0000002c #define AUART_LINECTRL 0x00000030 -#define AUART_LINECTRL_SET 0x00000034 -#define AUART_LINECTRL_CLR 0x00000038 -#define AUART_LINECTRL_TOG 0x0000003c #define AUART_LINECTRL2 0x00000040 -#define AUART_LINECTRL2_SET 0x00000044 -#define AUART_LINECTRL2_CLR 0x00000048 -#define AUART_LINECTRL2_TOG 0x0000004c #define AUART_INTR 0x00000050 -#define AUART_INTR_SET 0x00000054 -#define AUART_INTR_CLR 0x00000058 -#define AUART_INTR_TOG 0x0000005c #define AUART_DATA 0x00000060 #define AUART_STAT 0x00000070 #define AUART_DEBUG 0x00000080 @@ -136,11 +123,301 @@ #define AUART_STAT_FERR (1 << 16) #define AUART_STAT_RXCOUNT_MASK 0xffff +/* + * Start of Alphascale asm9260 defines + * This list contains only differences of existing bits + * between imx2x and asm9260 + */ +#define ASM9260_HW_CTRL0 0x0000 +/* + * RW. Tell the UART to execute the RX DMA Command. The + * UART will clear this bit at the end of receive execution. + */ +#define ASM9260_BM_CTRL0_RXDMA_RUN BIT(28) +/* RW. 0 use FIFO for status register; 1 use DMA */ +#define ASM9260_BM_CTRL0_RXTO_SOURCE_STATUS BIT(25) +/* + * RW. RX TIMEOUT Enable. Valid for FIFO and DMA. + * Warning: If this bit is set to 0, the RX timeout will not affect receive DMA + * operation. If this bit is set to 1, a receive timeout will cause the receive + * DMA logic to terminate by filling the remaining DMA bytes with garbage data. + */ +#define ASM9260_BM_CTRL0_RXTO_ENABLE BIT(24) +/* + * RW. Receive Timeout Counter Value: number of 8-bit-time to wait before + * asserting timeout on the RX input. If the RXFIFO is not empty and the RX + * input is idle, then the watchdog counter will decrement each bit-time. Note + * 7-bit-time is added to the programmed value, so a value of zero will set + * the counter to 7-bit-time, a value of 0x1 gives 15-bit-time and so on. Also + * note that the counter is reloaded at the end of each frame, so if the frame + * is 10 bits long and the timeout counter value is zero, then timeout will + * occur (when FIFO is not empty) even if the RX input is not idle. The default + * value is 0x3 (31 bit-time). + */ +#define ASM9260_BM_CTRL0_RXTO_MASK (0xff << 16) +/* TIMEOUT = (100*7+1)*(1/BAUD) */ +#define ASM9260_BM_CTRL0_DEFAULT_RXTIMEOUT (20 << 16) + +/* TX ctrl register */ +#define ASM9260_HW_CTRL1 0x0010 +/* + * RW. Tell the UART to execute the TX DMA Command. The + * UART will clear this bit at the end of transmit execution. + */ +#define ASM9260_BM_CTRL1_TXDMA_RUN BIT(28) + +#define ASM9260_HW_CTRL2 0x0020 +/* + * RW. Receive Interrupt FIFO Level Select. + * The trigger points for the receive interrupt are as follows: + * ONE_EIGHTHS = 0x0 Trigger on FIFO full to at least 2 of 16 entries. + * ONE_QUARTER = 0x1 Trigger on FIFO full to at least 4 of 16 entries. + * ONE_HALF = 0x2 Trigger on FIFO full to at least 8 of 16 entries. + * THREE_QUARTERS = 0x3 Trigger on FIFO full to at least 12 of 16 entries. + * SEVEN_EIGHTHS = 0x4 Trigger on FIFO full to at least 14 of 16 entries. + */ +#define ASM9260_BM_CTRL2_RXIFLSEL (7 << 20) +#define ASM9260_BM_CTRL2_DEFAULT_RXIFLSEL (3 << 20) +/* RW. Same as RXIFLSEL */ +#define ASM9260_BM_CTRL2_TXIFLSEL (7 << 16) +#define ASM9260_BM_CTRL2_DEFAULT_TXIFLSEL (2 << 16) +/* RW. Set DTR. When this bit is 1, the output is 0. */ +#define ASM9260_BM_CTRL2_DTR BIT(10) +/* RW. Loop Back Enable */ +#define ASM9260_BM_CTRL2_LBE BIT(7) +#define ASM9260_BM_CTRL2_PORT_ENABLE BIT(0) + +#define ASM9260_HW_LINECTRL 0x0030 +/* + * RW. Stick Parity Select. When bits 1, 2, and 7 of this register are set, the + * parity bit is transmitted and checked as a 0. When bits 1 and 7 are set, + * and bit 2 is 0, the parity bit is transmitted and checked as a 1. When this + * bit is cleared stick parity is disabled. + */ +#define ASM9260_BM_LCTRL_SPS BIT(7) +/* RW. Word length */ +#define ASM9260_BM_LCTRL_WLEN (3 << 5) +#define ASM9260_BM_LCTRL_CHRL_5 (0 << 5) +#define ASM9260_BM_LCTRL_CHRL_6 (1 << 5) +#define ASM9260_BM_LCTRL_CHRL_7 (2 << 5) +#define ASM9260_BM_LCTRL_CHRL_8 (3 << 5) + +/* + * Interrupt register. + * contains the interrupt enables and the interrupt status bits + */ +#define ASM9260_HW_INTR 0x0040 +/* Tx FIFO EMPTY Raw Interrupt enable */ +#define ASM9260_BM_INTR_TFEIEN BIT(27) +/* Overrun Error Interrupt Enable. */ +#define ASM9260_BM_INTR_OEIEN BIT(26) +/* Break Error Interrupt Enable. */ +#define ASM9260_BM_INTR_BEIEN BIT(25) +/* Parity Error Interrupt Enable. */ +#define ASM9260_BM_INTR_PEIEN BIT(24) +/* Framing Error Interrupt Enable. */ +#define ASM9260_BM_INTR_FEIEN BIT(23) + +/* nUARTDSR Modem Interrupt Enable. */ +#define ASM9260_BM_INTR_DSRMIEN BIT(19) +/* nUARTDCD Modem Interrupt Enable. */ +#define ASM9260_BM_INTR_DCDMIEN BIT(18) +/* nUARTRI Modem Interrupt Enable. */ +#define ASM9260_BM_INTR_RIMIEN BIT(16) +/* Auto-Boud Timeout */ +#define ASM9260_BM_INTR_ABTO BIT(13) +#define ASM9260_BM_INTR_ABEO BIT(12) +/* Tx FIFO EMPTY Raw Interrupt state */ +#define ASM9260_BM_INTR_TFEIS BIT(11) +/* Overrun Error */ +#define ASM9260_BM_INTR_OEIS BIT(10) +/* Break Error */ +#define ASM9260_BM_INTR_BEIS BIT(9) +/* Parity Error */ +#define ASM9260_BM_INTR_PEIS BIT(8) +/* Framing Error */ +#define ASM9260_BM_INTR_FEIS BIT(7) +#define ASM9260_BM_INTR_DSRMIS BIT(3) +#define ASM9260_BM_INTR_DCDMIS BIT(2) +#define ASM9260_BM_INTR_RIMIS BIT(0) + +/* + * RW. In DMA mode, up to 4 Received/Transmit characters can be accessed at a + * time. In PIO mode, only one character can be accessed at a time. The status + * register contains the receive data flags and valid bits. + */ +#define ASM9260_HW_DATA 0x0050 + +#define ASM9260_HW_STAT 0x0060 +/* RO. If 1, UARTAPP is present in this product. */ +#define ASM9260_BM_STAT_PRESENT BIT(31) +/* RO. If 1, HISPEED is present in this product. */ +#define ASM9260_BM_STAT_HISPEED BIT(30) +/* RO. Receive FIFO Full. */ +#define ASM9260_BM_STAT_RXFULL BIT(26) + +/* RO. The UART Debug Register contains the state of the DMA signals. */ +#define ASM9260_HW_DEBUG 0x0070 +/* DMA Command Run Status */ +#define ASM9260_BM_DEBUG_TXDMARUN BIT(5) +#define ASM9260_BM_DEBUG_RXDMARUN BIT(4) +/* DMA Command End Status */ +#define ASM9260_BM_DEBUG_TXCMDEND BIT(3) +#define ASM9260_BM_DEBUG_RXCMDEND BIT(2) +/* DMA Request Status */ +#define ASM9260_BM_DEBUG_TXDMARQ BIT(1) +#define ASM9260_BM_DEBUG_RXDMARQ BIT(0) + +#define ASM9260_HW_ILPR 0x0080 + +#define ASM9260_HW_RS485CTRL 0x0090 +/* + * RW. This bit reverses the polarity of the direction control signal on the RTS + * (or DTR) pin. + * If 0, The direction control pin will be driven to logic ‘0’ when the + * transmitter has data to be sent. It will be driven to logic ‘1’ after the + * last bit of data has been transmitted. + */ +#define ASM9260_BM_RS485CTRL_ONIV BIT(5) +/* RW. Enable Auto Direction Control. */ +#define ASM9260_BM_RS485CTRL_DIR_CTRL BIT(4) +/* + * RW. If 0 and DIR_CTRL = 1, pin RTS is used for direction control. + * If 1 and DIR_CTRL = 1, pin DTR is used for direction control. + */ +#define ASM9260_BM_RS485CTRL_PINSEL BIT(3) +/* RW. Enable Auto Address Detect (AAD). */ +#define ASM9260_BM_RS485CTRL_AADEN BIT(2) +/* RW. Disable receiver. */ +#define ASM9260_BM_RS485CTRL_RXDIS BIT(1) +/* RW. Enable RS-485/EIA-485 Normal Multidrop Mode (NMM) */ +#define ASM9260_BM_RS485CTRL_RS485EN BIT(0) + +#define ASM9260_HW_RS485ADRMATCH 0x00a0 +/* Contains the address match value. */ +#define ASM9260_BM_RS485ADRMATCH_MASK (0xff << 0) + +#define ASM9260_HW_RS485DLY 0x00b0 +/* + * RW. Contains the direction control (RTS or DTR) delay value. This delay time + * is in periods of the baud clock. + */ +#define ASM9260_BM_RS485DLY_MASK (0xff << 0) + +#define ASM9260_HW_AUTOBAUD 0x00c0 +/* WO. Auto-baud time-out interrupt clear bit. */ +#define ASM9260_BM_AUTOBAUD_TO_INT_CLR BIT(9) +/* WO. End of auto-baud interrupt clear bit. */ +#define ASM9260_BM_AUTOBAUD_EO_INT_CLR BIT(8) +/* Restart in case of timeout (counter restarts at next UART Rx falling edge) */ +#define ASM9260_BM_AUTOBAUD_AUTORESTART BIT(2) +/* Auto-baud mode select bit. 0 - Mode 0, 1 - Mode 1. */ +#define ASM9260_BM_AUTOBAUD_MODE BIT(1) +/* + * Auto-baud start (auto-baud is running). Auto-baud run bit. This bit is + * automatically cleared after auto-baud completion. + */ +#define ASM9260_BM_AUTOBAUD_START BIT(0) + +#define ASM9260_HW_CTRL3 0x00d0 +#define ASM9260_BM_CTRL3_OUTCLK_DIV_MASK (0xffff << 16) +/* + * RW. Provide clk over OUTCLK pin. In case of asm9260 it can be configured on + * pins 137 and 144. + */ +#define ASM9260_BM_CTRL3_MASTERMODE BIT(6) +/* RW. Baud Rate Mode: 1 - Enable sync mode. 0 - async mode. */ +#define ASM9260_BM_CTRL3_SYNCMODE BIT(4) +/* RW. 1 - MSB bit send frist; 0 - LSB bit frist. */ +#define ASM9260_BM_CTRL3_MSBF BIT(2) +/* RW. 1 - sample rate = 8 x Baudrate; 0 - sample rate = 16 x Baudrate. */ +#define ASM9260_BM_CTRL3_BAUD8 BIT(1) +/* RW. 1 - Set word length to 9bit. 0 - use ASM9260_BM_LCTRL_WLEN */ +#define ASM9260_BM_CTRL3_9BIT BIT(0) + +#define ASM9260_HW_ISO7816_CTRL 0x00e0 +/* RW. Enable High Speed mode. */ +#define ASM9260_BM_ISO7816CTRL_HS BIT(12) +/* Disable Successive Receive NACK */ +#define ASM9260_BM_ISO7816CTRL_DS_NACK BIT(8) +#define ASM9260_BM_ISO7816CTRL_MAX_ITER_MASK (0xff << 4) +/* Receive NACK Inhibit */ +#define ASM9260_BM_ISO7816CTRL_INACK BIT(3) +#define ASM9260_BM_ISO7816CTRL_NEG_DATA BIT(2) +/* RW. 1 - ISO7816 mode; 0 - USART mode */ +#define ASM9260_BM_ISO7816CTRL_ENABLE BIT(0) + +#define ASM9260_HW_ISO7816_ERRCNT 0x00f0 +/* Parity error counter. Will be cleared after reading */ +#define ASM9260_BM_ISO7816_NB_ERRORS_MASK (0xff << 0) + +#define ASM9260_HW_ISO7816_STATUS 0x0100 +/* Max number of Repetitions Reached */ +#define ASM9260_BM_ISO7816_STAT_ITERATION BIT(0) + +/* End of Alphascale asm9260 defines */ + static struct uart_driver auart_driver; enum mxs_auart_type { IMX23_AUART, IMX28_AUART, + ASM9260_AUART, +}; + +struct vendor_data { + const u16 *reg_offset; +}; + +enum { + REG_CTRL0, + REG_CTRL1, + REG_CTRL2, + REG_LINECTRL, + REG_LINECTRL2, + REG_INTR, + REG_DATA, + REG_STAT, + REG_DEBUG, + REG_VERSION, + REG_AUTOBAUD, + + /* The size of the array - must be last */ + REG_ARRAY_SIZE, +}; + +static const u16 mxs_asm9260_offsets[REG_ARRAY_SIZE] = { + [REG_CTRL0] = ASM9260_HW_CTRL0, + [REG_CTRL1] = ASM9260_HW_CTRL1, + [REG_CTRL2] = ASM9260_HW_CTRL2, + [REG_LINECTRL] = ASM9260_HW_LINECTRL, + [REG_INTR] = ASM9260_HW_INTR, + [REG_DATA] = ASM9260_HW_DATA, + [REG_STAT] = ASM9260_HW_STAT, + [REG_DEBUG] = ASM9260_HW_DEBUG, + [REG_AUTOBAUD] = ASM9260_HW_AUTOBAUD, +}; + +static const u16 mxs_stmp37xx_offsets[REG_ARRAY_SIZE] = { + [REG_CTRL0] = AUART_CTRL0, + [REG_CTRL1] = AUART_CTRL1, + [REG_CTRL2] = AUART_CTRL2, + [REG_LINECTRL] = AUART_LINECTRL, + [REG_LINECTRL2] = AUART_LINECTRL2, + [REG_INTR] = AUART_INTR, + [REG_DATA] = AUART_DATA, + [REG_STAT] = AUART_STAT, + [REG_DEBUG] = AUART_DEBUG, + [REG_VERSION] = AUART_VERSION, + [REG_AUTOBAUD] = AUART_AUTOBAUD, +}; + +static const struct vendor_data vendor_alphascale_asm9260 = { + .reg_offset = mxs_asm9260_offsets, +}; + +static const struct vendor_data vendor_freescale_stmp37xx = { + .reg_offset = mxs_stmp37xx_offsets, }; struct mxs_auart_port { @@ -153,8 +430,10 @@ struct mxs_auart_port { unsigned long flags; unsigned int mctrl_prev; enum mxs_auart_type devtype; + const struct vendor_data *vendor; struct clk *clk; + struct clk *clk_ahb; struct device *dev; /* for DMA */ @@ -174,6 +453,7 @@ struct mxs_auart_port { 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 }, + { .name = "as-auart-asm9260", .driver_data = ASM9260_AUART }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mxs_auart_devtype); @@ -185,6 +465,9 @@ static const struct of_device_id mxs_auart_dt_ids[] = { }, { .compatible = "fsl,imx23-auart", .data = &mxs_auart_devtype[IMX23_AUART] + }, { + .compatible = "alphascale,asm9260-auart", + .data = &mxs_auart_devtype[ASM9260_AUART] }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids); @@ -194,11 +477,54 @@ static inline int is_imx28_auart(struct mxs_auart_port *s) return s->devtype == IMX28_AUART; } +static inline int is_asm9260_auart(struct mxs_auart_port *s) +{ + return s->devtype == ASM9260_AUART; +} + static inline bool auart_dma_enabled(struct mxs_auart_port *s) { return s->flags & MXS_AUART_DMA_ENABLED; } +static unsigned int mxs_reg_to_offset(const struct mxs_auart_port *uap, + unsigned int reg) +{ + return uap->vendor->reg_offset[reg]; +} + +static unsigned int mxs_read(const struct mxs_auart_port *uap, + unsigned int reg) +{ + void __iomem *addr = uap->port.membase + mxs_reg_to_offset(uap, reg); + + return readl_relaxed(addr); +} + +static void mxs_write(unsigned int val, struct mxs_auart_port *uap, + unsigned int reg) +{ + void __iomem *addr = uap->port.membase + mxs_reg_to_offset(uap, reg); + + writel_relaxed(val, addr); +} + +static void mxs_set(unsigned int val, struct mxs_auart_port *uap, + unsigned int reg) +{ + void __iomem *addr = uap->port.membase + mxs_reg_to_offset(uap, reg); + + writel_relaxed(val, addr + SET_REG); +} + +static void mxs_clr(unsigned int val, struct mxs_auart_port *uap, + unsigned int reg) +{ + void __iomem *addr = uap->port.membase + mxs_reg_to_offset(uap, reg); + + writel_relaxed(val, addr + CLR_REG); +} + static void mxs_auart_stop_tx(struct uart_port *u); #define to_auart_port(u) container_of(u, struct mxs_auart_port, port) @@ -295,19 +621,16 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s) } - while (!(readl(s->port.membase + AUART_STAT) & - AUART_STAT_TXFF)) { + while (!(mxs_read(s, REG_STAT) & AUART_STAT_TXFF)) { if (s->port.x_char) { s->port.icount.tx++; - writel(s->port.x_char, - s->port.membase + AUART_DATA); + mxs_write(s->port.x_char, s, REG_DATA); s->port.x_char = 0; continue; } if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) { s->port.icount.tx++; - writel(xmit->buf[xmit->tail], - s->port.membase + AUART_DATA); + mxs_write(xmit->buf[xmit->tail], s, REG_DATA); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); } else break; @@ -316,11 +639,9 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s) uart_write_wakeup(&s->port); if (uart_circ_empty(&(s->port.state->xmit))) - writel(AUART_INTR_TXIEN, - s->port.membase + AUART_INTR_CLR); + mxs_clr(AUART_INTR_TXIEN, s, REG_INTR); else - writel(AUART_INTR_TXIEN, - s->port.membase + AUART_INTR_SET); + mxs_set(AUART_INTR_TXIEN, s, REG_INTR); if (uart_tx_stopped(&s->port)) mxs_auart_stop_tx(&s->port); @@ -332,8 +653,8 @@ static void mxs_auart_rx_char(struct mxs_auart_port *s) u32 stat; u8 c; - c = readl(s->port.membase + AUART_DATA); - stat = readl(s->port.membase + AUART_STAT); + c = mxs_read(s, REG_DATA); + stat = mxs_read(s, REG_STAT); flag = TTY_NORMAL; s->port.icount.rx++; @@ -368,7 +689,7 @@ static void mxs_auart_rx_char(struct mxs_auart_port *s) uart_insert_char(&s->port, stat, AUART_STAT_OERR, c, flag); out: - writel(stat, s->port.membase + AUART_STAT); + mxs_write(stat, s, REG_STAT); } static void mxs_auart_rx_chars(struct mxs_auart_port *s) @@ -376,13 +697,13 @@ static void mxs_auart_rx_chars(struct mxs_auart_port *s) u32 stat = 0; for (;;) { - stat = readl(s->port.membase + AUART_STAT); + stat = mxs_read(s, REG_STAT); if (stat & AUART_STAT_RXFE) break; mxs_auart_rx_char(s); } - writel(stat, s->port.membase + AUART_STAT); + mxs_write(stat, s, REG_STAT); tty_flip_buffer_push(&s->port.state->port); } @@ -418,7 +739,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) { struct mxs_auart_port *s = to_auart_port(u); - u32 ctrl = readl(u->membase + AUART_CTRL2); + u32 ctrl = mxs_read(s, REG_CTRL2); ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS); if (mctrl & TIOCM_RTS) { @@ -428,7 +749,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) ctrl |= AUART_CTRL2_RTS; } - writel(ctrl, u->membase + AUART_CTRL2); + mxs_write(ctrl, s, REG_CTRL2); mctrl_gpio_set(s->gpios, mctrl); } @@ -459,7 +780,7 @@ static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl) static u32 mxs_auart_get_mctrl(struct uart_port *u) { struct mxs_auart_port *s = to_auart_port(u); - u32 stat = readl(u->membase + AUART_STAT); + u32 stat = mxs_read(s, REG_STAT); u32 mctrl = 0; if (stat & AUART_STAT_CTS) @@ -536,14 +857,14 @@ static void dma_rx_callback(void *arg) dma_unmap_sg(s->dev, &s->rx_sgl, 1, DMA_FROM_DEVICE); - stat = readl(s->port.membase + AUART_STAT); + stat = mxs_read(s, REG_STAT); stat &= ~(AUART_STAT_OERR | AUART_STAT_BERR | AUART_STAT_PERR | AUART_STAT_FERR); count = stat & AUART_STAT_RXCOUNT_MASK; tty_insert_flip_string(port, s->rx_dma_buf, count); - writel(stat, s->port.membase + AUART_STAT); + mxs_write(stat, s, REG_STAT); tty_flip_buffer_push(port); /* start the next DMA for RX. */ @@ -606,8 +927,8 @@ static void mxs_auart_dma_exit_channel(struct mxs_auart_port *s) static void mxs_auart_dma_exit(struct mxs_auart_port *s) { - writel(AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE | AUART_CTRL2_DMAONERR, - s->port.membase + AUART_CTRL2_CLR); + mxs_clr(AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE | AUART_CTRL2_DMAONERR, + s, REG_CTRL2); mxs_auart_dma_exit_channel(s); s->flags &= ~MXS_AUART_DMA_ENABLED; @@ -666,7 +987,7 @@ static void mxs_auart_settermios(struct uart_port *u, cflag = termios->c_cflag; ctrl = AUART_LINECTRL_FEN; - ctrl2 = readl(u->membase + AUART_CTRL2); + ctrl2 = mxs_read(s, REG_CTRL2); /* byte size */ switch (cflag & CSIZE) { @@ -754,15 +1075,24 @@ static void mxs_auart_settermios(struct uart_port *u, } /* set baud rate */ - baud_min = DIV_ROUND_UP(u->uartclk * 32, AUART_LINECTRL_BAUD_DIV_MAX); - baud_max = u->uartclk * 32 / AUART_LINECTRL_BAUD_DIV_MIN; - baud = uart_get_baud_rate(u, termios, old, baud_min, baud_max); - div = u->uartclk * 32 / baud; + if (is_asm9260_auart(s)) { + baud = uart_get_baud_rate(u, termios, old, + u->uartclk * 4 / 0x3FFFFF, + u->uartclk / 16); + div = u->uartclk * 4 / baud; + } else { + baud_min = DIV_ROUND_UP(u->uartclk * 32, + AUART_LINECTRL_BAUD_DIV_MAX); + baud_max = u->uartclk * 32 / AUART_LINECTRL_BAUD_DIV_MIN; + baud = uart_get_baud_rate(u, termios, old, baud_min, baud_max); + div = u->uartclk * 32 / baud; + } + ctrl |= AUART_LINECTRL_BAUD_DIVFRAC(div & 0x3F); ctrl |= AUART_LINECTRL_BAUD_DIVINT(div >> 6); + mxs_write(ctrl, s, REG_LINECTRL); - writel(ctrl, u->membase + AUART_LINECTRL); - writel(ctrl2, u->membase + AUART_CTRL2); + mxs_write(ctrl2, s, REG_CTRL2); uart_update_timeout(u, termios->c_cflag, baud); @@ -771,8 +1101,8 @@ static void mxs_auart_settermios(struct uart_port *u, !test_and_set_bit(MXS_AUART_DMA_RX_READY, &s->flags)) { if (!mxs_auart_dma_prep_rx(s)) { /* Disable the normal RX interrupt. */ - writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN, - u->membase + AUART_INTR_CLR); + mxs_clr(AUART_INTR_RXIEN | AUART_INTR_RTIEN, + s, REG_INTR); } else { mxs_auart_dma_exit(s); dev_err(s->dev, "We can not start up the DMA.\n"); @@ -802,16 +1132,13 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) u32 istat; struct mxs_auart_port *s = context; u32 mctrl_temp = s->mctrl_prev; - u32 stat = readl(s->port.membase + AUART_STAT); + u32 stat = mxs_read(s, REG_STAT); - istat = readl(s->port.membase + AUART_INTR); + istat = mxs_read(s, REG_INTR); /* ack irq */ - writel(istat & (AUART_INTR_RTIS - | AUART_INTR_TXIS - | AUART_INTR_RXIS - | AUART_INTR_CTSMIS), - s->port.membase + AUART_INTR_CLR); + mxs_clr(istat & (AUART_INTR_RTIS | AUART_INTR_TXIS | AUART_INTR_RXIS + | AUART_INTR_CTSMIS), s, REG_INTR); /* * Dealing with GPIO interrupt @@ -827,8 +1154,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) if (CTS_AT_AUART() && s->ms_irq_enabled) uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS); - writel(AUART_INTR_CTSMIS, - s->port.membase + AUART_INTR_CLR); + mxs_clr(AUART_INTR_CTSMIS, s, REG_INTR); istat &= ~AUART_INTR_CTSMIS; } @@ -846,44 +1172,44 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) return IRQ_HANDLED; } -static void mxs_auart_reset_deassert(struct uart_port *u) +static void mxs_auart_reset_deassert(struct mxs_auart_port *s) { int i; unsigned int reg; - writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_CLR); + mxs_clr(AUART_CTRL0_SFTRST, s, REG_CTRL0); for (i = 0; i < 10000; i++) { - reg = readl(u->membase + AUART_CTRL0); + reg = mxs_read(s, REG_CTRL0); if (!(reg & AUART_CTRL0_SFTRST)) break; udelay(3); } - writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); + mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0); } -static void mxs_auart_reset_assert(struct uart_port *u) +static void mxs_auart_reset_assert(struct mxs_auart_port *s) { int i; u32 reg; - reg = readl(u->membase + AUART_CTRL0); + reg = mxs_read(s, REG_CTRL0); /* if already in reset state, keep it untouched */ if (reg & AUART_CTRL0_SFTRST) return; - writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); - writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_SET); + mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0); + mxs_set(AUART_CTRL0_SFTRST, s, REG_CTRL0); for (i = 0; i < 1000; i++) { - reg = readl(u->membase + AUART_CTRL0); + reg = mxs_read(s, REG_CTRL0); /* reset is finished when the clock is gated */ if (reg & AUART_CTRL0_CLKGATE) return; udelay(10); } - dev_err(u->dev, "Failed to reset the unit."); + dev_err(s->dev, "Failed to reset the unit."); } static int mxs_auart_startup(struct uart_port *u) @@ -896,17 +1222,17 @@ static int mxs_auart_startup(struct uart_port *u) return ret; if (uart_console(u)) { - writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); + mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0); } else { /* reset the unit to a well known state */ - mxs_auart_reset_assert(u); - mxs_auart_reset_deassert(u); + mxs_auart_reset_assert(s); + mxs_auart_reset_deassert(s); } - writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET); + mxs_set(AUART_CTRL2_UARTEN, s, REG_CTRL2); - writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, - u->membase + AUART_INTR); + mxs_write(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, + s, REG_INTR); /* Reset FIFO size (it could have changed if DMA was enabled) */ u->fifosize = MXS_AUART_FIFO_SIZE; @@ -915,7 +1241,7 @@ static int mxs_auart_startup(struct uart_port *u) * Enable fifo so all four bytes of a DMA word are written to * output (otherwise, only the LSB is written, ie. 1 in 4 bytes) */ - writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET); + mxs_set(AUART_LINECTRL_FEN, s, REG_LINECTRL); /* get initial status of modem lines */ mctrl_gpio_get(s->gpios, &s->mctrl_prev); @@ -934,12 +1260,13 @@ static void mxs_auart_shutdown(struct uart_port *u) mxs_auart_dma_exit(s); if (uart_console(u)) { - writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR); - writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, - u->membase + AUART_INTR_CLR); - writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); + mxs_clr(AUART_CTRL2_UARTEN, s, REG_CTRL2); + + mxs_clr(AUART_INTR_RXIEN | AUART_INTR_RTIEN | + AUART_INTR_CTSMIEN, s, REG_INTR); + mxs_set(AUART_CTRL0_CLKGATE, s, REG_CTRL0); } else { - mxs_auart_reset_assert(u); + mxs_auart_reset_assert(s); } clk_disable_unprepare(s->clk); @@ -947,7 +1274,9 @@ static void mxs_auart_shutdown(struct uart_port *u) static unsigned int mxs_auart_tx_empty(struct uart_port *u) { - if ((readl(u->membase + AUART_STAT) & + struct mxs_auart_port *s = to_auart_port(u); + + if ((mxs_read(s, REG_STAT) & (AUART_STAT_TXFE | AUART_STAT_BUSY)) == AUART_STAT_TXFE) return TIOCSER_TEMT; @@ -959,29 +1288,33 @@ static void mxs_auart_start_tx(struct uart_port *u) struct mxs_auart_port *s = to_auart_port(u); /* enable transmitter */ - writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET); + mxs_set(AUART_CTRL2_TXE, s, REG_CTRL2); mxs_auart_tx_chars(s); } static void mxs_auart_stop_tx(struct uart_port *u) { - writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_CLR); + struct mxs_auart_port *s = to_auart_port(u); + + mxs_clr(AUART_CTRL2_TXE, s, REG_CTRL2); } static void mxs_auart_stop_rx(struct uart_port *u) { - writel(AUART_CTRL2_RXE, u->membase + AUART_CTRL2_CLR); + struct mxs_auart_port *s = to_auart_port(u); + + mxs_clr(AUART_CTRL2_RXE, s, REG_CTRL2); } static void mxs_auart_break_ctl(struct uart_port *u, int ctl) { + struct mxs_auart_port *s = to_auart_port(u); + if (ctl) - writel(AUART_LINECTRL_BRK, - u->membase + AUART_LINECTRL_SET); + mxs_set(AUART_LINECTRL_BRK, s, REG_LINECTRL); else - writel(AUART_LINECTRL_BRK, - u->membase + AUART_LINECTRL_CLR); + mxs_clr(AUART_LINECTRL_BRK, s, REG_LINECTRL); } static struct uart_ops mxs_auart_ops = { @@ -1009,15 +1342,16 @@ static struct mxs_auart_port *auart_port[MXS_AUART_PORTS]; #ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE static void mxs_auart_console_putchar(struct uart_port *port, int ch) { + struct mxs_auart_port *s = to_auart_port(port); unsigned int to = 1000; - while (readl(port->membase + AUART_STAT) & AUART_STAT_TXFF) { + while (mxs_read(s, REG_STAT) & AUART_STAT_TXFF) { if (!to--) break; udelay(1); } - writel(ch, port->membase + AUART_DATA); + mxs_write(ch, s, REG_DATA); } static void @@ -1037,18 +1371,16 @@ auart_console_write(struct console *co, const char *str, unsigned int count) clk_enable(s->clk); /* First save the CR then disable the interrupts */ - old_ctrl2 = readl(port->membase + AUART_CTRL2); - old_ctrl0 = readl(port->membase + AUART_CTRL0); + old_ctrl2 = mxs_read(s, REG_CTRL2); + old_ctrl0 = mxs_read(s, REG_CTRL0); - writel(AUART_CTRL0_CLKGATE, - port->membase + AUART_CTRL0_CLR); - writel(AUART_CTRL2_UARTEN | AUART_CTRL2_TXE, - port->membase + AUART_CTRL2_SET); + mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0); + mxs_set(AUART_CTRL2_UARTEN | AUART_CTRL2_TXE, s, REG_CTRL2); uart_console_write(port, str, count, mxs_auart_console_putchar); /* Finally, wait for transmitter to become empty ... */ - while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) { + while (mxs_read(s, REG_STAT) & AUART_STAT_BUSY) { udelay(1); if (!to--) break; @@ -1060,24 +1392,25 @@ auart_console_write(struct console *co, const char *str, unsigned int count) * unused, but that is better than to disable it while it is still * transmitting. */ - if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) { - writel(old_ctrl0, port->membase + AUART_CTRL0); - writel(old_ctrl2, port->membase + AUART_CTRL2); + if (!(mxs_read(s, REG_STAT) & AUART_STAT_BUSY)) { + mxs_write(old_ctrl0, s, REG_CTRL0); + mxs_write(old_ctrl2, s, REG_CTRL2); } clk_disable(s->clk); } static void __init -auart_console_get_options(struct uart_port *port, int *baud, +auart_console_get_options(struct mxs_auart_port *s, int *baud, int *parity, int *bits) { + struct uart_port *port = &s->port; unsigned int lcr_h, quot; - if (!(readl(port->membase + AUART_CTRL2) & AUART_CTRL2_UARTEN)) + if (!(mxs_read(s, REG_CTRL2) & AUART_CTRL2_UARTEN)) return; - lcr_h = readl(port->membase + AUART_LINECTRL); + lcr_h = mxs_read(s, REG_LINECTRL); *parity = 'n'; if (lcr_h & AUART_LINECTRL_PEN) { @@ -1092,12 +1425,10 @@ auart_console_get_options(struct uart_port *port, int *baud, else *bits = 8; - quot = ((readl(port->membase + AUART_LINECTRL) - & AUART_LINECTRL_BAUD_DIVINT_MASK)) - >> (AUART_LINECTRL_BAUD_DIVINT_SHIFT - 6); - quot |= ((readl(port->membase + AUART_LINECTRL) - & AUART_LINECTRL_BAUD_DIVFRAC_MASK)) - >> AUART_LINECTRL_BAUD_DIVFRAC_SHIFT; + quot = ((mxs_read(s, REG_LINECTRL) & AUART_LINECTRL_BAUD_DIVINT_MASK)) + >> (AUART_LINECTRL_BAUD_DIVINT_SHIFT - 6); + quot |= ((mxs_read(s, REG_LINECTRL) & AUART_LINECTRL_BAUD_DIVFRAC_MASK)) + >> AUART_LINECTRL_BAUD_DIVFRAC_SHIFT; if (quot == 0) quot = 1; @@ -1132,7 +1463,7 @@ auart_console_setup(struct console *co, char *options) if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else - auart_console_get_options(&s->port, &baud, &parity, &bits); + auart_console_get_options(s, &baud, &parity, &bits); ret = uart_set_options(&s->port, co, baud, parity, bits, flow); @@ -1164,6 +1495,60 @@ static struct uart_driver auart_driver = { #endif }; +static void mxs_init_regs(struct mxs_auart_port *s) +{ + if (is_asm9260_auart(s)) + s->vendor = &vendor_alphascale_asm9260; + else + s->vendor = &vendor_freescale_stmp37xx; +} + +static int mxs_get_clks(struct mxs_auart_port *s, + struct platform_device *pdev) +{ + int err; + + if (!is_asm9260_auart(s)) { + s->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(s->clk)) + return PTR_ERR(s->clk); + + return 0; + } + + s->clk = devm_clk_get(s->dev, "mod"); + if (IS_ERR(s->clk)) { + dev_err(s->dev, "Failed to get \"mod\" clk\n"); + return PTR_ERR(s->clk); + } + + s->clk_ahb = devm_clk_get(s->dev, "ahb"); + if (IS_ERR(s->clk_ahb)) { + dev_err(s->dev, "Failed to get \"ahb\" clk\n"); + return PTR_ERR(s->clk_ahb); + } + + err = clk_prepare_enable(s->clk_ahb); + if (err) { + dev_err(s->dev, "Failed to enable ahb_clk!\n"); + return err; + } + + err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb)); + if (err) { + dev_err(s->dev, "Failed to set rate!\n"); + return err; + } + + err = clk_prepare_enable(s->clk); + if (err) { + dev_err(s->dev, "Failed to enable clk!\n"); + return err; + } + + return 0; +} + /* * This function returns 1 if pdev isn't a device instatiated by dt, 0 if it * could successfully get all information from dt or a negative errno. @@ -1269,6 +1654,9 @@ static int mxs_auart_probe(struct platform_device *pdev) if (!s) return -ENOMEM; + s->port.dev = &pdev->dev; + s->dev = &pdev->dev; + ret = serial_mxs_probe_dt(s, pdev); if (ret > 0) s->port.line = pdev->id < 0 ? 0 : pdev->id; @@ -1280,15 +1668,14 @@ static int mxs_auart_probe(struct platform_device *pdev) s->devtype = pdev->id_entry->driver_data; } - s->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(s->clk)) - return PTR_ERR(s->clk); + ret = mxs_get_clks(s, pdev); + if (ret) + return ret; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) return -ENXIO; - s->port.mapbase = r->start; s->port.membase = ioremap(r->start, resource_size(r)); s->port.ops = &mxs_auart_ops; @@ -1296,7 +1683,8 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.fifosize = MXS_AUART_FIFO_SIZE; s->port.uartclk = clk_get_rate(s->clk); s->port.type = PORT_IMX; - s->port.dev = s->dev = &pdev->dev; + + mxs_init_regs(s); s->mctrl_prev = 0; @@ -1327,16 +1715,21 @@ static int mxs_auart_probe(struct platform_device *pdev) auart_port[s->port.line] = s; - mxs_auart_reset_deassert(&s->port); + mxs_auart_reset_deassert(s); ret = uart_add_one_port(&auart_driver, &s->port); if (ret) goto out_free_gpio_irq; - version = readl(s->port.membase + AUART_VERSION); - dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n", - (version >> 24) & 0xff, - (version >> 16) & 0xff, version & 0xffff); + /* ASM9260 don't have version reg */ + if (is_asm9260_auart(s)) { + dev_info(&pdev->dev, "Found APPUART ASM9260\n"); + } else { + version = mxs_read(s, REG_VERSION); + dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n", + (version >> 24) & 0xff, + (version >> 16) & 0xff, version & 0xffff); + } return 0; -- cgit v1.1 From 06ed48b7ee0c1b3c1dee6f2c90333109cf7db6ac Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 18 Apr 2016 16:55:37 +0200 Subject: TTY: add __init attribute Add __init attribute on a function that is only called from other __init functions and that is not inlined, at least with gcc version 4.8.4 on an x86 machine with allyesconfig. Currently, the function is put in the .text.unlikely segment. Declaring it as __init will cause it to be put in the .init.text and to disappear after initialization. The result of objdump -x on the function before the change is as follows: 000000000000014c l F .text.unlikely 0000000000000a2e init_r_port And after the change it is as follows: 0000000000000000 l F .init.text 0000000000000a29 init_r_port Done with the help of Coccinelle. The semantic patch checks for local static non-init functions that are called from an __init function and are not called from any other function. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/rocket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 7f3b1db..b0cc47c 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -615,7 +615,8 @@ static void rp_do_poll(unsigned long dummy) * the board. * Inputs: board, aiop, chan numbers */ -static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) +static void __init +init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) { unsigned rocketMode; struct r_port *info; -- cgit v1.1 From e881d3f3fafc849356ecd1e3a2f3bf669476ed2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 24 Mar 2016 14:24:20 +0100 Subject: serial: imx: fix polarity of RI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When in DTE mode, the bit USR2_RIIN is active low. So invert the logic accordingly. Fixes: 90ebc4838666 ("serial: imx: repair and complete handshaking") Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 66cc3d1..7cfb482 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -800,9 +800,9 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport) if (!(usr1 & USR2_DCDIN)) tmp |= TIOCM_CAR; - /* in DCE mode RIIN is always 0 */ - if (readl(sport->port.membase + USR2) & USR2_RIIN) - tmp |= TIOCM_RI; + if (sport->dte_mode) + if (!(readl(sport->port.membase + USR2) & USR2_RIIN)) + tmp |= TIOCM_RI; return tmp; } -- cgit v1.1 From 4d845a62b3f5672a813777b8dbebca0bad456bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 24 Mar 2016 14:24:21 +0100 Subject: serial: imx: let irq handler return IRQ_NONE if no event was handled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gives the irq core a chance to disable the serial interrupt in case an event isn't cleared in the handler. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 7cfb482..4676916 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -737,6 +737,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) struct imx_port *sport = dev_id; unsigned int sts; unsigned int sts2; + irqreturn_t ret = IRQ_NONE; sts = readl(sport->port.membase + USR1); sts2 = readl(sport->port.membase + USR2); @@ -746,26 +747,34 @@ static irqreturn_t imx_int(int irq, void *dev_id) imx_dma_rxint(sport); else imx_rxint(irq, dev_id); + ret = IRQ_HANDLED; } if ((sts & USR1_TRDY && readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) || (sts2 & USR2_TXDC && - readl(sport->port.membase + UCR4) & UCR4_TCEN)) + readl(sport->port.membase + UCR4) & UCR4_TCEN)) { imx_txint(irq, dev_id); + ret = IRQ_HANDLED; + } - if (sts & USR1_RTSD) + if (sts & USR1_RTSD) { imx_rtsint(irq, dev_id); + ret = IRQ_HANDLED; + } - if (sts & USR1_AWAKE) + if (sts & USR1_AWAKE) { writel(USR1_AWAKE, sport->port.membase + USR1); + ret = IRQ_HANDLED; + } if (sts2 & USR2_ORE) { sport->port.icount.overrun++; writel(USR2_ORE, sport->port.membase + USR2); + ret = IRQ_HANDLED; } - return IRQ_HANDLED; + return ret; } /* -- cgit v1.1 From 16804d68bfaa7f5f5a73ab4a016ffeba33e87770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 24 Mar 2016 14:24:22 +0100 Subject: serial: imx: make sure unhandled irqs are disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that events that are not handled in the irq function don't trigger an interrupt. When the serial port is operated in DTE mode, the events for DCD and RI events are enabled after a system reset by default. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 4676916..aa07301 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1224,11 +1224,32 @@ static int imx_startup(struct uart_port *port) temp |= (UCR2_RXEN | UCR2_TXEN); if (!sport->have_rtscts) temp |= UCR2_IRTS; + /* + * make sure the edge sensitive RTS-irq is disabled, + * we're using RTSD instead. + */ + if (!is_imx1_uart(sport)) + temp &= ~UCR2_RTSEN; writel(temp, sport->port.membase + UCR2); if (!is_imx1_uart(sport)) { temp = readl(sport->port.membase + UCR3); - temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; + + /* + * The effect of RI and DCD differs depending on the UFCR_DCEDTE + * bit. In DCE mode they control the outputs, in DTE mode they + * enable the respective irqs. At least the DCD irq cannot be + * cleared on i.MX25 at least, so it's not usable and must be + * disabled. I don't have test hardware to check if RI has the + * same problem but I consider this likely so it's disabled for + * now, too. + */ + temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | + UCR3_RI | UCR3_DCD; + + if (sport->dte_mode) + temp &= ~(UCR3_RI | UCR3_DCD); + writel(temp, sport->port.membase + UCR3); } -- cgit v1.1 From 9ec8efe94b5c6a797aa5bceca337373d310f9c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 24 Mar 2016 14:24:23 +0100 Subject: serial: imx: only count 0->1 transitions for RNG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to tty_ioctl(4) (from man-pages 4.04) the rng member only counts 0->1 transitions. For the other signals (DSR, CD, CTS) both edges are supposed to be counted. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index aa07301..8ec8127 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -887,7 +887,7 @@ static void imx_mctrl_check(struct imx_port *sport) sport->old_status = status; - if (changed & TIOCM_RI) + if (changed & TIOCM_RI && status & TIOCM_RI) sport->port.icount.rng++; if (changed & TIOCM_DSR) sport->port.icount.dsr++; -- cgit v1.1 From 66f95884928bd1b4114531b7a472601acf285130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 24 Mar 2016 14:24:24 +0100 Subject: serial: imx: reorder functions to simplify next patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 98 ++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 8ec8127..161e9ed 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -732,6 +732,55 @@ static void imx_dma_rxint(struct imx_port *sport) spin_unlock_irqrestore(&sport->port.lock, flags); } +/* + * We have a modem side uart, so the meanings of RTS and CTS are inverted. + */ +static unsigned int imx_get_hwmctrl(struct imx_port *sport) +{ + unsigned int tmp = TIOCM_DSR; + unsigned usr1 = readl(sport->port.membase + USR1); + + if (usr1 & USR1_RTSS) + tmp |= TIOCM_CTS; + + /* in DCE mode DCDIN is always 0 */ + if (!(usr1 & USR2_DCDIN)) + tmp |= TIOCM_CAR; + + if (sport->dte_mode) + if (!(readl(sport->port.membase + USR2) & USR2_RIIN)) + tmp |= TIOCM_RI; + + return tmp; +} + +/* + * Handle any change of modem status signal since we were last called. + */ +static void imx_mctrl_check(struct imx_port *sport) +{ + unsigned int status, changed; + + status = imx_get_hwmctrl(sport); + changed = status ^ sport->old_status; + + if (changed == 0) + return; + + sport->old_status = status; + + if (changed & TIOCM_RI && status & TIOCM_RI) + sport->port.icount.rng++; + if (changed & TIOCM_DSR) + sport->port.icount.dsr++; + if (changed & TIOCM_CAR) + uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); + if (changed & TIOCM_CTS) + uart_handle_cts_change(&sport->port, status & TIOCM_CTS); + + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); +} + static irqreturn_t imx_int(int irq, void *dev_id) { struct imx_port *sport = dev_id; @@ -794,28 +843,6 @@ static unsigned int imx_tx_empty(struct uart_port *port) return ret; } -/* - * We have a modem side uart, so the meanings of RTS and CTS are inverted. - */ -static unsigned int imx_get_hwmctrl(struct imx_port *sport) -{ - unsigned int tmp = TIOCM_DSR; - unsigned usr1 = readl(sport->port.membase + USR1); - - if (usr1 & USR1_RTSS) - tmp |= TIOCM_CTS; - - /* in DCE mode DCDIN is always 0 */ - if (!(usr1 & USR2_DCDIN)) - tmp |= TIOCM_CAR; - - if (sport->dte_mode) - if (!(readl(sport->port.membase + USR2) & USR2_RIIN)) - tmp |= TIOCM_RI; - - return tmp; -} - static unsigned int imx_get_mctrl(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -873,33 +900,6 @@ static void imx_break_ctl(struct uart_port *port, int break_state) } /* - * Handle any change of modem status signal since we were last called. - */ -static void imx_mctrl_check(struct imx_port *sport) -{ - unsigned int status, changed; - - status = imx_get_hwmctrl(sport); - changed = status ^ sport->old_status; - - if (changed == 0) - return; - - sport->old_status = status; - - if (changed & TIOCM_RI && status & TIOCM_RI) - sport->port.icount.rng++; - if (changed & TIOCM_DSR) - sport->port.icount.dsr++; - if (changed & TIOCM_CAR) - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - if (changed & TIOCM_CTS) - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -} - -/* * This is our per-port timeout handler, for checking the * modem status signals. */ -- cgit v1.1 From 27e16501052e5341934d3d327d580dc9a90f1212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 24 Mar 2016 14:24:25 +0100 Subject: serial: imx: implement DSR irq handling for DTE mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable reporting of DSR events (which is named DTR in the registers because Freescale uses the names as seem from a DCE). Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 161e9ed..4b38392 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -114,6 +114,7 @@ #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ +#define UCR3_DTRDEN (1<<3) /* Data Terminal Ready Delta Enable. */ #define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */ #define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ #define UCR3_BPEN (1<<0) /* Preset registers enable */ @@ -142,7 +143,7 @@ #define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ #define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ #define USR1_AGTIM (1<<8) /* Ageing timer interrupt flag */ -#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ +#define USR1_DTRD (1<<7) /* DTR Delta */ #define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ #define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ #define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ @@ -807,6 +808,19 @@ static irqreturn_t imx_int(int irq, void *dev_id) ret = IRQ_HANDLED; } + if (sts & USR1_DTRD) { + unsigned long flags; + + if (sts & USR1_DTRD) + writel(USR1_DTRD, sport->port.membase + USR1); + + spin_lock_irqsave(&sport->port.lock, flags); + imx_mctrl_check(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); + + ret = IRQ_HANDLED; + } + if (sts & USR1_RTSD) { imx_rtsint(irq, dev_id); ret = IRQ_HANDLED; @@ -1205,7 +1219,7 @@ static int imx_startup(struct uart_port *port) /* * Finally, clear and enable interrupts */ - writel(USR1_RTSD, sport->port.membase + USR1); + writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1); writel(USR2_ORE, sport->port.membase + USR2); if (sport->dma_is_inited && !sport->dma_is_enabled) @@ -1245,7 +1259,7 @@ static int imx_startup(struct uart_port *port) * now, too. */ temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | - UCR3_RI | UCR3_DCD; + UCR3_DTRDEN | UCR3_RI | UCR3_DCD; if (sport->dte_mode) temp &= ~(UCR3_RI | UCR3_DCD); -- cgit v1.1 From 98952bf510d0c7cdfc284f098bbf4682dc47bc61 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 25 Mar 2016 14:35:49 -0700 Subject: tty: serial: msm: Support more bauds The msm_find_best_baud() function is written with the assumption that the port->uartclk rate is fixed to a particular rate at boot time, but now this driver changes that clk rate at runtime when the baud is changed. The way the hardware works is that an input clk rate comes from the clk controller into the uart hw block. That rate is typically 1843200 or 3686400 Hz. That rate can then be divided by an internal divider in the hw block to achieve a particular baud on the serial wire. msm_find_best_baud() is looking for that divider value. A few things are wrong with the way the code is written. First, it assumes that the maximum baud that the uart can support if the clk rate is fixed at boot is 460800, which would correspond to an input clk rate of 230400 * 16 == 3686400 Hz. Except some devices have a boot rate of 1843200 Hz or max baud of 115200, so achieving 230400 on those devices doesn't work at all because we don't increase the clk rate unless max baud is 460800. Second, we can't achieve bauds higher than 460800 that require anything besides a divisor of 1, because we always call msm_find_best_baud() with a fixed port->uartclk rate that will eventually be changed after we calculate the divisor. So if we need to get a baud of 500000, we'll just multiply that by 16 and hope that the clk can give us 500000 * 16 == 8000000 Hz, which it typically can't do. To really achieve 500000 baud, we need to get an input clk rate of 24000000 Hz and then divide that by 3 inside the uart hardware. Finally, we return success for bauds even when we can't actually achieve them. This means that when the user asks for 500000 baud, we actually get 921600 right now, but the user doesn't know that. Fix all of this by searching through the divisor and clk rate space with a combination of clk_round_rate() and baud calculations, keeping track of the best clk rate and divisor we find if we can't get an exact match. Typically we can get an exact match with a divisor of 1, but sometimes we need to keep track and try more frequencies. On my msm8916 device, this results in all standard bauds in baud_table being supported except for 1800, 576000, 1152000, and 4000000. Fixes: 850b37a71bde ("tty: serial: msm: Remove 115.2 Kbps maximum baud rate limitation") Cc: "Ivan T. Ivanov" Cc: Matthew McClintock Signed-off-by: Stephen Boyd Tested-by: Srinivas Kandagatla Acked-by: Andy Gross Acked-by: Bjorn Andersson Tested-by: Cristian Prundeanu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 99 +++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 074c797..b7d80bd 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -861,37 +861,72 @@ struct msm_baud_map { }; static const struct msm_baud_map * -msm_find_best_baud(struct uart_port *port, unsigned int baud) +msm_find_best_baud(struct uart_port *port, unsigned int baud, + unsigned long *rate) { - unsigned int i, divisor; - const struct msm_baud_map *entry; + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int divisor, result; + unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX; + const struct msm_baud_map *entry, *end, *best; static const struct msm_baud_map table[] = { - { 1536, 0x00, 1 }, - { 768, 0x11, 1 }, - { 384, 0x22, 1 }, - { 192, 0x33, 1 }, - { 96, 0x44, 1 }, - { 48, 0x55, 1 }, - { 32, 0x66, 1 }, - { 24, 0x77, 1 }, - { 16, 0x88, 1 }, - { 12, 0x99, 6 }, - { 8, 0xaa, 6 }, - { 6, 0xbb, 6 }, - { 4, 0xcc, 6 }, - { 3, 0xdd, 8 }, - { 2, 0xee, 16 }, { 1, 0xff, 31 }, - { 0, 0xff, 31 }, + { 2, 0xee, 16 }, + { 3, 0xdd, 8 }, + { 4, 0xcc, 6 }, + { 6, 0xbb, 6 }, + { 8, 0xaa, 6 }, + { 12, 0x99, 6 }, + { 16, 0x88, 1 }, + { 24, 0x77, 1 }, + { 32, 0x66, 1 }, + { 48, 0x55, 1 }, + { 96, 0x44, 1 }, + { 192, 0x33, 1 }, + { 384, 0x22, 1 }, + { 768, 0x11, 1 }, + { 1536, 0x00, 1 }, }; - divisor = uart_get_divisor(port, baud); + best = table; /* Default to smallest divider */ + target = clk_round_rate(msm_port->clk, 16 * baud); + divisor = DIV_ROUND_CLOSEST(target, 16 * baud); + + end = table + ARRAY_SIZE(table); + entry = table; + while (entry < end) { + if (entry->divisor <= divisor) { + result = target / entry->divisor / 16; + diff = abs(result - baud); + + /* Keep track of best entry */ + if (diff < best_diff) { + best_diff = diff; + best = entry; + best_rate = target; + } - for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++) - if (entry->divisor <= divisor) - break; + if (result == baud) + break; + } else if (entry->divisor > divisor) { + old = target; + target = clk_round_rate(msm_port->clk, old + 1); + /* + * The rate didn't get any faster so we can't do + * better at dividing it down + */ + if (target == old) + break; + + /* Start the divisor search over at this new rate */ + entry = table; + divisor = DIV_ROUND_CLOSEST(target, 16 * baud); + continue; + } + entry++; + } - return entry; /* Default to smallest divider */ + *rate = best_rate; + return best; } static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, @@ -900,22 +935,20 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, unsigned int rxstale, watermark, mask; struct msm_port *msm_port = UART_TO_MSM(port); const struct msm_baud_map *entry; - unsigned long flags; - - entry = msm_find_best_baud(port, baud); - - msm_write(port, entry->code, UART_CSR); - - if (baud > 460800) - port->uartclk = baud * 16; + unsigned long flags, rate; flags = *saved_flags; spin_unlock_irqrestore(&port->lock, flags); - clk_set_rate(msm_port->clk, port->uartclk); + entry = msm_find_best_baud(port, baud, &rate); + clk_set_rate(msm_port->clk, rate); + baud = rate / 16 / entry->divisor; spin_lock_irqsave(&port->lock, flags); *saved_flags = flags; + port->uartclk = rate; + + msm_write(port, entry->code, UART_CSR); /* RX stale watermark */ rxstale = entry->rxstale; -- cgit v1.1 From f5b556c94c8490d42fea79d7b4ae0ecbc291e69d Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 24 Mar 2016 16:02:52 +0100 Subject: MIPS: ath79: make bootconsole wait for both THRE and TEMT This makes the ath79 bootconsole behave the same way as the generic 8250 bootconsole. Also waiting for TEMT (transmit buffer is empty) instead of just THRE (transmit buffer is not full) ensures that all characters have been transmitted before the real serial driver starts reconfiguring the serial controller (which would sometimes result in garbage being transmitted.) This change does not cause a visible performance loss. In addition, this seems to fix a hang observed in certain configurations on many AR7xxx/AR9xxx SoCs during autoconfig of the real serial driver. A more complete follow-up patch will disable 8250 autoconfig for ath79 altogether (the serial controller is detected as a 16550A, which is not fully compatible with the ath79 serial, and the autoconfig may lead to undefined behavior on ath79.) Cc: Signed-off-by: Matthias Schiffer Signed-off-by: Greg Kroah-Hartman --- arch/mips/ath79/early_printk.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c index b955faf..d1adc59 100644 --- a/arch/mips/ath79/early_printk.c +++ b/arch/mips/ath79/early_printk.c @@ -31,13 +31,15 @@ static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val) } while (1); } +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + static void prom_putchar_ar71xx(unsigned char ch) { void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE)); - prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE); + prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY); __raw_writel(ch, base + UART_TX * 4); - prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE); + prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY); } static void prom_putchar_ar933x(unsigned char ch) -- cgit v1.1 From b8995f527aac143e83d3900ff39357651ea4e0f6 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 21 Apr 2016 18:58:31 +0900 Subject: serial: samsung: Reorder the sequence of clock control when call s3c24xx_serial_set_termios() This patch fixes the broken serial log when changing the clock source of uart device. Before disabling the original clock source, this patch enables the new clock source to protect the clock off state for a split second. Signed-off-by: Chanwoo Choi Reviewed-by: Marek Szyprowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index ac7f8df..99bb231 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1271,6 +1271,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, /* check to see if we need to change clock source */ if (ourport->baudclk != clk) { + clk_prepare_enable(clk); + s3c24xx_serial_setsource(port, clk_sel); if (!IS_ERR(ourport->baudclk)) { @@ -1278,8 +1280,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, ourport->baudclk = ERR_PTR(-EINVAL); } - clk_prepare_enable(clk); - ourport->baudclk = clk; ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; } -- cgit v1.1 From 182846a00f489849c55d113954f0c4a8a286ca39 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 31 Mar 2016 10:08:14 +0200 Subject: tty: vt, remove reduntant check MAX_NR_CONSOLES and MAX_NR_USER_CONSOLES are both 63 since they were introduced in 1.1.54. And since vc_allocate does: if (currcons >= MAX_NR_CONSOLES) return -ENXIO; if (!vc_cons[currcons].d) { if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) return -EPERM; } the second check is pointless. Remove both the check and the macro MAX_NR_USER_CONSOLES. Signed-off-by: Jiri Slaby Reported-by: Fugang Duan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 4 ---- include/uapi/linux/vt.h | 1 - 2 files changed, 5 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3e3c757..90305d5 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -768,10 +768,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ struct vc_data *vc; struct vt_notifier_param param; - /* prevent users from taking too much memory */ - if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) - return -EPERM; - /* due to the granularity of kmalloc, we waste some memory here */ /* the alloc is done in two steps, to optimize the common situation of a 25x80 console (structsize=216, screenbuf_size=4000) */ diff --git a/include/uapi/linux/vt.h b/include/uapi/linux/vt.h index 978578b..f690348 100644 --- a/include/uapi/linux/vt.h +++ b/include/uapi/linux/vt.h @@ -8,7 +8,6 @@ */ #define MIN_NR_CONSOLES 1 /* must be at least 1 */ #define MAX_NR_CONSOLES 63 /* serial lines start at 64 */ -#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */ /* Note: the ioctl VT_GETSTATE does not work for consoles 16 and higher (since it returns a short) */ -- cgit v1.1 From 34902b7f2754e6d890feb0cee34187f1bc75c930 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 31 Mar 2016 10:08:15 +0200 Subject: tty: vt, get rid of weird source code flow Some code in vc_allocate is indented by 4 spaces. It is inside a condition. Invert the condition and move the code to the first indentation level (using \tab). And insert some empty lines to have logical code blocks separated. Then, instead of freeing in an 'if' false branch, use goto-error label as fail path. Maybe better to look at this patch with diff -w -b. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 70 +++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 90305d5..d1da391 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -760,46 +760,54 @@ static void visual_init(struct vc_data *vc, int num, int init) int vc_allocate(unsigned int currcons) /* return 0 on success */ { + struct vt_notifier_param param; + struct vc_data *vc; + WARN_CONSOLE_UNLOCKED(); if (currcons >= MAX_NR_CONSOLES) return -ENXIO; - if (!vc_cons[currcons].d) { - struct vc_data *vc; - struct vt_notifier_param param; - - /* due to the granularity of kmalloc, we waste some memory here */ - /* the alloc is done in two steps, to optimize the common situation - of a 25x80 console (structsize=216, screenbuf_size=4000) */ - /* although the numbers above are not valid since long ago, the - point is still up-to-date and the comment still has its value - even if only as a historical artifact. --mj, July 1998 */ - param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL); - if (!vc) + + if (vc_cons[currcons].d) + return 0; + + /* due to the granularity of kmalloc, we waste some memory here */ + /* the alloc is done in two steps, to optimize the common situation + of a 25x80 console (structsize=216, screenbuf_size=4000) */ + /* although the numbers above are not valid since long ago, the + point is still up-to-date and the comment still has its value + even if only as a historical artifact. --mj, July 1998 */ + param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL); + if (!vc) return -ENOMEM; - vc_cons[currcons].d = vc; - tty_port_init(&vc->port); - INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); - visual_init(vc, currcons, 1); - if (!*vc->vc_uni_pagedir_loc) + + vc_cons[currcons].d = vc; + tty_port_init(&vc->port); + INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); + + visual_init(vc, currcons, 1); + + if (!*vc->vc_uni_pagedir_loc) con_set_default_unimap(vc); - vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); - if (!vc->vc_screenbuf) { - kfree(vc); - vc_cons[currcons].d = NULL; - return -ENOMEM; - } - /* If no drivers have overridden us and the user didn't pass a - boot option, default to displaying the cursor */ - if (global_cursor_default == -1) - global_cursor_default = 1; + vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); + if (!vc->vc_screenbuf) + goto err_free; + + /* If no drivers have overridden us and the user didn't pass a + boot option, default to displaying the cursor */ + if (global_cursor_default == -1) + global_cursor_default = 1; + + vc_init(vc, vc->vc_rows, vc->vc_cols, 1); + vcs_make_sysfs(currcons); + atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); - vc_init(vc, vc->vc_rows, vc->vc_cols, 1); - vcs_make_sysfs(currcons); - atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); - } return 0; +err_free: + kfree(vc); + vc_cons[currcons].d = NULL; + return -ENOMEM; } static inline int resize_screen(struct vc_data *vc, int width, int height, -- cgit v1.1 From 8ede5cce4f0baff77ef63aa3cb3afc65d0317e0b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 31 Mar 2016 10:08:16 +0200 Subject: tty: vt, make color_table const This means all ->con_set_palette have to have the second parameter const too now. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/usb/misc/sisusbvga/sisusb_con.c | 2 +- drivers/video/console/fbcon.c | 4 ++-- drivers/video/console/mdacon.c | 2 +- drivers/video/console/newport_con.c | 2 +- drivers/video/console/sticon.c | 2 +- drivers/video/console/vgacon.c | 5 ++--- include/linux/console.h | 2 +- include/linux/selection.h | 2 +- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index d1da391..2c71b3b 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1039,7 +1039,7 @@ struct vc_data *vc_deallocate(unsigned int currcons) #define VT100ID "\033[?1;2c" #define VT102ID "\033[?6c" -unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, +const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15 }; /* the default colour table, for VGA+ colour systems */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index ace3430..afa8532 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -601,7 +601,7 @@ sisusbcon_save_screen(struct vc_data *c) /* interface routine */ static int -sisusbcon_set_palette(struct vc_data *c, unsigned char *table) +sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) { struct sisusb_usb_data *sisusb; int i, j; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 6e92917..afd3301 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -170,7 +170,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, int height, int width); static int fbcon_switch(struct vc_data *vc); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); -static int fbcon_set_palette(struct vc_data *vc, unsigned char *table); +static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table); static int fbcon_scrolldelta(struct vc_data *vc, int lines); /* @@ -2652,7 +2652,7 @@ static struct fb_cmap palette_cmap = { 0, 16, palette_red, palette_green, palette_blue, NULL }; -static int fbcon_set_palette(struct vc_data *vc, unsigned char *table) +static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; int i, j, k, depth; diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 296e945..8edc062 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -481,7 +481,7 @@ static int mdacon_switch(struct vc_data *c) return 1; /* redrawing needed */ } -static int mdacon_set_palette(struct vc_data *c, unsigned char *table) +static int mdacon_set_palette(struct vc_data *c, const unsigned char *table) { return -EINVAL; } diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index bb4e962..0553dfe 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -574,7 +574,7 @@ static int newport_font_set(struct vc_data *vc, struct console_font *font, unsig return newport_set_font(vc->vc_num, font); } -static int newport_set_palette(struct vc_data *vc, unsigned char *table) +static int newport_set_palette(struct vc_data *vc, const unsigned char *table) { return -EINVAL; } diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 026fd12..e440c2d 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -79,7 +79,7 @@ static const char *sticon_startup(void) return "STI console"; } -static int sticon_set_palette(struct vc_data *c, unsigned char *table) +static int sticon_set_palette(struct vc_data *c, const unsigned char *table) { return -EINVAL; } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 517f565..8bf9110 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -80,7 +80,6 @@ static void vgacon_deinit(struct vc_data *c); static void vgacon_cursor(struct vc_data *c, int mode); static int vgacon_switch(struct vc_data *c); static int vgacon_blank(struct vc_data *c, int blank, int mode_switch); -static int vgacon_set_palette(struct vc_data *vc, unsigned char *table); static int vgacon_scrolldelta(struct vc_data *c, int lines); static int vgacon_set_origin(struct vc_data *c); static void vgacon_save_screen(struct vc_data *c); @@ -847,7 +846,7 @@ static int vgacon_switch(struct vc_data *c) return 0; /* Redrawing not needed */ } -static void vga_set_palette(struct vc_data *vc, unsigned char *table) +static void vga_set_palette(struct vc_data *vc, const unsigned char *table) { int i, j; @@ -860,7 +859,7 @@ static void vga_set_palette(struct vc_data *vc, unsigned char *table) } } -static int vgacon_set_palette(struct vc_data *vc, unsigned char *table) +static int vgacon_set_palette(struct vc_data *vc, const unsigned char *table) { #ifdef CAN_LOAD_PALETTE if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked diff --git a/include/linux/console.h b/include/linux/console.h index ea731af..137ac1a 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -47,7 +47,7 @@ struct consw { int (*con_font_copy)(struct vc_data *, int); int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); - int (*con_set_palette)(struct vc_data *, unsigned char *); + int (*con_set_palette)(struct vc_data *, const unsigned char *); int (*con_scrolldelta)(struct vc_data *, int); int (*con_set_origin)(struct vc_data *); void (*con_save_screen)(struct vc_data *); diff --git a/include/linux/selection.h b/include/linux/selection.h index 85193aa..7e6c445 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -24,7 +24,7 @@ extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); extern int console_blanked; -extern unsigned char color_table[]; +extern const unsigned char color_table[]; extern int default_red[]; extern int default_grn[]; extern int default_blu[]; -- cgit v1.1 From 91e74ca5e7ac4ec6c61b84d6618eb5e401f852f0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 31 Mar 2016 10:08:17 +0200 Subject: tty: vt, use proper type for default colors Every user of default_red, default_grn, and default_blu treats them as unsigned char. So make it really unsigned char. And indent the initializers and module_param properly. This saves ~ 100 bytes of data. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 27 +++++++++++++++++---------- include/linux/selection.h | 6 +++--- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 2c71b3b..8f9f8ed 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1043,16 +1043,23 @@ const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15 }; /* the default colour table, for VGA+ colour systems */ -int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, - 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; -int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, - 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; -int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, - 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; - -module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR); -module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR); -module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR); +unsigned char default_red[] = { + 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, + 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff +}; +module_param_array(default_red, byte, NULL, S_IRUGO | S_IWUSR); + +unsigned char default_grn[] = { + 0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa, + 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff +}; +module_param_array(default_grn, byte, NULL, S_IRUGO | S_IWUSR); + +unsigned char default_blu[] = { + 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff +}; +module_param_array(default_blu, byte, NULL, S_IRUGO | S_IWUSR); /* * gotoxy() must verify all boundaries, because the arguments diff --git a/include/linux/selection.h b/include/linux/selection.h index 7e6c445..8e4624e 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -25,9 +25,9 @@ extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); extern int console_blanked; extern const unsigned char color_table[]; -extern int default_red[]; -extern int default_grn[]; -extern int default_blu[]; +extern unsigned char default_red[]; +extern unsigned char default_grn[]; +extern unsigned char default_blu[]; extern unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed); extern u16 screen_glyph(struct vc_data *vc, int offset); -- cgit v1.1 From eeeabba024191c810b83592578cfc6183c4059fa Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 31 Mar 2016 10:23:34 +0200 Subject: TTY: serial/ifx6x60, initialize more In ifx_spi_complete, 'more' is not initialized. It is set only if the status is clear and only if the header is parsed OK. If any of those is not true, 'more' can be used uninitialized in that function later. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ifx6x60.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 2085a6c..d386346 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -651,7 +651,7 @@ static void ifx_spi_complete(void *ctx) struct ifx_spi_device *ifx_dev = ctx; int length; int actual_length; - unsigned char more; + unsigned char more = 0; unsigned char cts; int local_write_pending = 0; int queue_length; -- cgit v1.1 From 144ef5c2df9b473dad7eab375adcf5b11d0b1e47 Mon Sep 17 00:00:00 2001 From: Wan Ahmad Zainie Date: Wed, 6 Apr 2016 12:06:51 +0800 Subject: serial: 8250: export get_mctrl function Exposes get_mctrl() function so that it can be overriden with platform specific implementation. Signed-off-by: Wan Ahmad Zainie Reviewed-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 3 +++ drivers/tty/serial/8250/8250_port.c | 10 +++++++++- include/linux/serial_8250.h | 2 ++ include/linux/serial_core.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 2f4f5ee..0fbd7c0 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -830,6 +830,7 @@ static int serial8250_probe(struct platform_device *dev) uart.port.handle_irq = p->handle_irq; uart.port.handle_break = p->handle_break; uart.port.set_termios = p->set_termios; + uart.port.get_mctrl = p->get_mctrl; uart.port.pm = p->pm; uart.port.dev = &dev->dev; uart.port.irqflags |= irqflag; @@ -1022,6 +1023,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) /* Possibly override set_termios call */ if (up->port.set_termios) uart->port.set_termios = up->port.set_termios; + if (up->port.get_mctrl) + uart->port.get_mctrl = up->port.get_mctrl; if (up->port.set_mctrl) uart->port.set_mctrl = up->port.set_mctrl; if (up->port.startup) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 00ad263..a803ddf 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1882,7 +1882,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; } -static unsigned int serial8250_get_mctrl(struct uart_port *port) +unsigned int serial8250_do_get_mctrl(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned int status; @@ -1903,6 +1903,14 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port) ret |= TIOCM_CTS; return ret; } +EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl); + +static unsigned int serial8250_get_mctrl(struct uart_port *port) +{ + if (port->get_mctrl) + return port->get_mctrl(port); + return serial8250_do_get_mctrl(port); +} void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) { diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 4348797..48ec765 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -36,6 +36,7 @@ struct plat_serial8250_port { void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); + unsigned int (*get_mctrl)(struct uart_port *); int (*handle_irq)(struct uart_port *); void (*pm)(struct uart_port *, unsigned int state, unsigned old); @@ -148,6 +149,7 @@ extern int early_serial8250_setup(struct earlycon_device *device, const char *options); extern void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old); +extern unsigned int serial8250_do_get_mctrl(struct uart_port *port); extern int serial8250_do_startup(struct uart_port *port); extern void serial8250_do_shutdown(struct uart_port *port); extern void serial8250_do_pm(struct uart_port *port, unsigned int state, diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index fd4ad4d..a3d7c0d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -123,6 +123,7 @@ struct uart_port { void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); + unsigned int (*get_mctrl)(struct uart_port *); void (*set_mctrl)(struct uart_port *, unsigned int); int (*startup)(struct uart_port *port); void (*shutdown)(struct uart_port *port); -- cgit v1.1 From c2684ed7d0e908e7c8dad7f199922d342ea55c66 Mon Sep 17 00:00:00 2001 From: Wan Ahmad Zainie Date: Wed, 6 Apr 2016 12:06:52 +0800 Subject: serial: 8250_pci: report DCD and DSR signals as active for Bay Trail Bay Trail UART port does not support DCD and DSR lines. The driver shall report that these signals are permanently active. This patch is for HSUART enumerated via PCI. For ACPI, see commit dfd37668ea6d ("serial: 8250_dw: Fix get_mctrl behaviour"). The commit also describes the possible issue if these signals are enabled on a port without these pins. Signed-off-by: Wan Ahmad Zainie Acked-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 4eedd1d..0cf5123 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1416,6 +1416,17 @@ static bool byt_dma_filter(struct dma_chan *chan, void *param) return true; } +static unsigned int +byt_get_mctrl(struct uart_port *port) +{ + unsigned int ret = serial8250_do_get_mctrl(port); + + /* Force DCD and DSR signals to permanently be reported as active. */ + ret |= TIOCM_CAR | TIOCM_DSR; + + return ret; +} + static int byt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1480,6 +1491,7 @@ byt_serial_setup(struct serial_private *priv, port->port.type = PORT_16550A; port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); port->port.set_termios = byt_set_termios; + port->port.get_mctrl = byt_get_mctrl; port->port.fifosize = 64; port->tx_loadsz = 64; port->dma = dma; -- cgit v1.1 From 107e15fc1f8d6ef69eac5f175971252f76e82f0d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Apr 2016 17:35:09 +0300 Subject: serial: 8250_mid: use proper bar for DNV platform Unlike Intel Medfield and Tangier platforms DNV uses PCI BAR0 for IO compatible resources and BAR1 for MMIO. We need latter in a way to support DMA. Introduce an additional field in the internal structure and pass PCI BAR based on device ID. Reported-by: "Lai, Poey Seng" Fixes: 6ede6dcd87aa ("serial: 8250_mid: add support for DMA engine handling from UART MMIO") Cc: stable@vger.kernel.org Reviewed-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mid.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 88531a3..7aa6ef8 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -14,6 +14,7 @@ #include #include +#include #include "8250.h" @@ -31,6 +32,7 @@ struct mid8250; struct mid8250_board { + unsigned int flags; unsigned long freq; unsigned int base_baud; int (*setup)(struct mid8250 *, struct uart_port *p); @@ -106,12 +108,13 @@ static int dnv_setup(struct mid8250 *mid, struct uart_port *p) { struct hsu_dma_chip *chip = &mid->dma_chip; struct pci_dev *pdev = to_pci_dev(p->dev); + unsigned int bar = FL_GET_BASE(mid->board->flags); int ret; chip->dev = &pdev->dev; chip->irq = pdev->irq; chip->regs = p->membase; - chip->length = pci_resource_len(pdev, 0); + chip->length = pci_resource_len(pdev, bar); chip->offset = DNV_DMA_CHAN_OFFSET; /* Falling back to PIO mode if DMA probing fails */ @@ -217,6 +220,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct uart_8250_port uart; struct mid8250 *mid; + unsigned int bar; int ret; ret = pcim_enable_device(pdev); @@ -230,6 +234,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; mid->board = (struct mid8250_board *)id->driver_data; + bar = FL_GET_BASE(mid->board->flags); memset(&uart, 0, sizeof(struct uart_8250_port)); @@ -242,8 +247,8 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE; uart.port.set_termios = mid8250_set_termios; - uart.port.mapbase = pci_resource_start(pdev, 0); - uart.port.membase = pcim_iomap(pdev, 0, 0); + uart.port.mapbase = pci_resource_start(pdev, bar); + uart.port.membase = pcim_iomap(pdev, bar, 0); if (!uart.port.membase) return -ENOMEM; @@ -282,18 +287,21 @@ static void mid8250_remove(struct pci_dev *pdev) } static const struct mid8250_board pnw_board = { + .flags = FL_BASE0, .freq = 50000000, .base_baud = 115200, .setup = pnw_setup, }; static const struct mid8250_board tng_board = { + .flags = FL_BASE0, .freq = 38400000, .base_baud = 1843200, .setup = tng_setup, }; static const struct mid8250_board dnv_board = { + .flags = FL_BASE1, .freq = 133333333, .base_baud = 115200, .setup = dnv_setup, -- cgit v1.1 From c42850f1ae7e70056f852e67bb9dddf927853b47 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Apr 2016 17:35:10 +0300 Subject: serial: 8250_mid: recognize interrupt source in handler There is a special register that shows interrupt status by source. In particular case the source can be a combination of DMA Tx, DMA Rx, and UART. Read the register and call the handlers only for sources that request an interrupt. Fixes: 6ede6dcd87aa ("serial: 8250_mid: add support for DMA engine handling from UART MMIO") Cc: stable@vger.kernel.org Reviewed-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mid.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 7aa6ef8..ed48988 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -25,6 +25,7 @@ #define PCI_DEVICE_ID_INTEL_DNV_UART 0x19d8 /* Intel MID Specific registers */ +#define INTEL_MID_UART_DNV_FISR 0x08 #define INTEL_MID_UART_PS 0x30 #define INTEL_MID_UART_MUL 0x34 #define INTEL_MID_UART_DIV 0x38 @@ -90,16 +91,16 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p) static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; - int ret; - - ret = hsu_dma_irq(&mid->dma_chip, 0); - ret |= hsu_dma_irq(&mid->dma_chip, 1); - - /* For now, letting the HW generate separate interrupt for the UART */ - if (ret) - return ret; - - return serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); + unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); + int ret = IRQ_NONE; + + if (fisr & BIT(2)) + ret |= hsu_dma_irq(&mid->dma_chip, 1); + if (fisr & BIT(1)) + ret |= hsu_dma_irq(&mid->dma_chip, 0); + if (fisr & BIT(0)) + ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); + return ret; } #define DNV_DMA_CHAN_OFFSET 0x80 -- cgit v1.1 From dea5ac3ae44f46a4ce3558cb4f48fa7b0a598d46 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Apr 2016 17:35:11 +0300 Subject: serial: 8250_mid: include missed linux/bitops.h The BIT() macro, that is definded in bitops.h, is used in the driver. Include necessary header for that. While here, reorder included headers alphabetically. Reviewed-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index ed48988..e812237 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -9,9 +9,10 @@ * published by the Free Software Foundation. */ -#include +#include #include #include +#include #include #include -- cgit v1.1 From 1fc969c759861ac491b6c93116aa497f774b00dc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Apr 2016 17:35:12 +0300 Subject: serial: 8250_mid: make module available only on X86 There is no reason to compile module on non-X86 platforms, though COMPILE_TEST is provided for sake of what it does. While here, set default to SERIAL_8250 that user doesn't need an explicit option to be set and hide it from non-expert. Reviewed-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 4d7cb9c..7f33d349 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -398,8 +398,10 @@ config SERIAL_8250_INGENIC its UARTs, say Y to this option. If unsure, say N. config SERIAL_8250_MID - tristate "Support for serial ports on Intel MID platforms" + tristate "Support for serial ports on Intel MID platforms" if EXPERT + default SERIAL_8250 depends on SERIAL_8250 && PCI + depends on X86 || COMPILE_TEST select HSU_DMA if SERIAL_8250_DMA select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID) select RATIONAL -- cgit v1.1 From ceeafb8e222f4ea73981ca0bf9f29882cb0c34b2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Apr 2016 17:35:13 +0300 Subject: serial: 8250_mid: correct comment regarding Tangier HSU On Intel Penwell and Tangier the HSU block (3 HSU ports) has a global register set which is currently not used by the driver. On Tangier it has it's own PCI device and thus available for enumeration. Since it's not a real HSU port we just skip it and therefore put a comment in the code why we do so. Reviewed-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mid.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index e812237..86379a7 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -80,7 +80,11 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p) struct pci_dev *pdev = to_pci_dev(p->dev); int index = PCI_FUNC(pdev->devfn); - /* Currently no support for HSU port0 */ + /* + * Device 0000:00:04.0 is not a real HSU port. It provides a global + * register set for all HSU ports, although it has the same PCI ID. + * Skip it here. + */ if (index-- == 0) return -ENODEV; -- cgit v1.1 From a86f50ed35a8854f964393e60526c16744e2ed2c Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 20:49:41 -0700 Subject: serial: 8250: Eliminate needless local in irq handlers dma_err is not used other than for boolean evaluation; substitute the actual operation directly. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 8 ++------ drivers/tty/serial/8250/8250_port.c | 6 +----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 6f76051..7c8c886 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1033,7 +1033,6 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) unsigned char status; unsigned long flags; u8 iir; - int dma_err = 0; serial8250_rpm_get(up); @@ -1048,9 +1047,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) status = serial_port_in(port, UART_LSR); if (status & (UART_LSR_DR | UART_LSR_BI)) { - - dma_err = omap_8250_rx_dma(up, iir); - if (dma_err) { + if (omap_8250_rx_dma(up, iir)) { status = serial8250_rx_chars(up, status); omap_8250_rx_dma(up, 0); } @@ -1066,8 +1063,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) * try again due to an earlier failer which * might have been resolved by now. */ - dma_err = omap_8250_tx_dma(up); - if (dma_err) + if (omap_8250_tx_dma(up)) serial8250_tx_chars(up); } } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index a803ddf..40d2d30 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1796,7 +1796,6 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) unsigned char status; unsigned long flags; struct uart_8250_port *up = up_to_u8250p(port); - int dma_err = 0; if (iir & UART_IIR_NO_INT) return 0; @@ -1808,10 +1807,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) DEBUG_INTR("status = %x...", status); if (status & (UART_LSR_DR | UART_LSR_BI)) { - if (up->dma) - dma_err = up->dma->rx_dma(up, iir); - - if (!up->dma || dma_err) + if (!up->dma || up->dma->rx_dma(up, iir)) status = serial8250_rx_chars(up, status); } serial8250_modem_status(up); -- cgit v1.1 From d601744dc145a27945e97d643d2f5d298ab40627 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 20:49:42 -0700 Subject: serial: 8250: Reduce expr in 8250 irq handler If !up->dma == F, then up->dma == T and can be elided from the (up->dma && up->dma->tx_err) sub-expression. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 40d2d30..b2bbb9d 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1811,8 +1811,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial8250_rx_chars(up, status); } serial8250_modem_status(up); - if ((!up->dma || (up->dma && up->dma->tx_err)) && - (status & UART_LSR_THRE)) + if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE)) serial8250_tx_chars(up); spin_unlock_irqrestore(&port->lock, flags); -- cgit v1.1 From f56f0a54b013ae03a9f9b7701e2ce65aea674889 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 20:49:43 -0700 Subject: serial: omap8250: Eliminate local in omap8250_runtime_resume() Eliminate 'loss_cntx' local variable. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 7c8c886..abeaf5e 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1403,16 +1403,14 @@ static int omap8250_runtime_resume(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up; - int loss_cntx; /* In case runtime-pm tries this before we are setup */ if (!priv) return 0; up = serial8250_get_port(priv->line); - loss_cntx = omap8250_lost_context(up); - if (loss_cntx) + if (omap8250_lost_context(up)) omap8250_restore_regs(up); if (up->dma && up->dma->rxchan) -- cgit v1.1 From 9c5895057bfe5d033c65e15d13c7eee4a78cc837 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 20:49:44 -0700 Subject: serial: 8250: Remove unused define HIGH_BITS_OFFSET is only used in the serial core; remove from 8250- specific header. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 047a7ba..8739d22 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -84,7 +84,6 @@ struct serial8250_config { #define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ #define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */ -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) #ifdef CONFIG_SERIAL_8250_SHARE_IRQ #define SERIAL8250_SHARE_IRQS 1 -- cgit v1.1 From 76bbdcb35ebb0e9c5315c4b249cd883cca9e065d Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 6 Apr 2016 12:25:39 +0100 Subject: tty: ipwireless: fix possible NULL dereference The function alloc_ctrl_packet() can fail and return NULL. Incase it fails print an error message and exit. Signed-off-by: Sudip Mukherjee Reviewed-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/tty/ipwireless/hardware.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index ad7031a..df0204b 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -1572,6 +1572,11 @@ static void handle_received_SETUP_packet(struct ipw_hardware *hw, sizeof(struct ipw_setup_reboot_msg_ack), ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, TL_SETUP_SIGNO_REBOOT_MSG_ACK); + if (!packet) { + pr_err(IPWIRELESS_PCCARD_NAME + ": Not enough memory to send reboot packet"); + break; + } packet->header.length = sizeof(struct TlSetupRebootMsgAck); send_packet(hw, PRIO_SETUP, &packet->header); -- cgit v1.1 From 423314337acde8ddda6324f0917b306642b3ef6c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 6 Apr 2016 11:44:04 +0100 Subject: tty: synclink: remove unneeded test We reach this point of code after a test of 'info->port.tty->hw_stopped', we do not need to test for 'info->port.tty' as it is obvious that info->port.tty is not NULL now, we have already dereferenced it. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/tty/synclink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index bc4bc1f..00d91d12 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -1361,8 +1361,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) if (status & MISCSTATUS_CTS) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx start..."); - if (info->port.tty) - info->port.tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; usc_start_transmitter(info); info->pending_bh |= BH_TRANSMIT; return; -- cgit v1.1 From fab794aeb60f5069a026fad8a4ff7c1cdf5b8713 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Apr 2016 09:44:31 +0300 Subject: tty: hvc_console: silence unintialized variable warning If ->get_char() returns a negative error code and that can mean that "ch" is uninitialized. The callers of this function expect NO_POLL_CHAR on error so let's return that. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 209dad8..ce86487 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -814,7 +814,7 @@ static int hvc_poll_get_char(struct tty_driver *driver, int line) n = hp->ops->get_chars(hp->vtermno, &ch, 1); - if (n == 0) + if (n <= 0) return NO_POLL_CHAR; return ch; -- cgit v1.1 From 1681d2116c96d07b69bf2730271f3161153a6670 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 21 Apr 2016 15:13:19 +0900 Subject: serial: 8250_uniphier: add "\n" at the end of error log Just in case. Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 1b7bd26..efd1f9c 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -209,7 +209,7 @@ static int uniphier_uart_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "failed to get IRQ number"); + dev_err(dev, "failed to get IRQ number\n"); return irq; } -- cgit v1.1 From 973ea59e8c466c54b6d1f0a080f3efda418cdc18 Mon Sep 17 00:00:00 2001 From: Maarten Brock Date: Fri, 22 Apr 2016 18:19:33 +0200 Subject: serial-uartlite: Constify uartlite_be/uartlite_le Made uartlite_be and uartlite_le constants. Signed-off-by: Maarten Brock Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/uartlite.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index d08baa6..05089b6 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -72,7 +72,7 @@ static void uartlite_outbe32(u32 val, void __iomem *addr) iowrite32be(val, addr); } -static struct uartlite_reg_ops uartlite_be = { +static const struct uartlite_reg_ops uartlite_be = { .in = uartlite_inbe32, .out = uartlite_outbe32, }; @@ -87,21 +87,21 @@ static void uartlite_outle32(u32 val, void __iomem *addr) iowrite32(val, addr); } -static struct uartlite_reg_ops uartlite_le = { +static const struct uartlite_reg_ops uartlite_le = { .in = uartlite_inle32, .out = uartlite_outle32, }; static inline u32 uart_in32(u32 offset, struct uart_port *port) { - struct uartlite_reg_ops *reg_ops = port->private_data; + const struct uartlite_reg_ops *reg_ops = port->private_data; return reg_ops->in(port->membase + offset); } static inline void uart_out32(u32 val, u32 offset, struct uart_port *port) { - struct uartlite_reg_ops *reg_ops = port->private_data; + const struct uartlite_reg_ops *reg_ops = port->private_data; reg_ops->out(val, port->membase + offset); } @@ -345,13 +345,13 @@ static int ulite_request_port(struct uart_port *port) return -EBUSY; } - port->private_data = &uartlite_be; + port->private_data = (void *)&uartlite_be; ret = uart_in32(ULITE_CONTROL, port); uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port); ret = uart_in32(ULITE_STATUS, port); /* Endianess detection */ if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY) - port->private_data = &uartlite_le; + port->private_data = (void *)&uartlite_le; return 0; } -- cgit v1.1 From 78bca84b95d65fb1407de418d0ed2203736dee1a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 17:29:16 +0200 Subject: serial: Move Marvell UART DT bindings to correct location All other UART DT binding documentation is under Documentation/devicetree/bindings/serial/. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/mvebu-uart.txt | 13 +++++++++++++ Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 Documentation/devicetree/bindings/serial/mvebu-uart.txt delete mode 100644 Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt new file mode 100644 index 0000000..6087def --- /dev/null +++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt @@ -0,0 +1,13 @@ +* Marvell UART : Non standard UART used in some of Marvell EBU SoCs (e.g., Armada-3700) + +Required properties: +- compatible: "marvell,armada-3700-uart" +- reg: offset and length of the register set for the device. +- interrupts: device interrupt + +Example: + serial@12000 { + compatible = "marvell,armada-3700-uart"; + reg = <0x12000 0x400>; + interrupts = <43>; + }; diff --git a/Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt deleted file mode 100644 index 6087def..0000000 --- a/Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt +++ /dev/null @@ -1,13 +0,0 @@ -* Marvell UART : Non standard UART used in some of Marvell EBU SoCs (e.g., Armada-3700) - -Required properties: -- compatible: "marvell,armada-3700-uart" -- reg: offset and length of the register set for the device. -- interrupts: device interrupt - -Example: - serial@12000 { - compatible = "marvell,armada-3700-uart"; - reg = <0x12000 0x400>; - interrupts = <43>; - }; -- cgit v1.1 From 06c5e362ce1fbb29cb9505b4a1191d9489d8bdd2 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 28 Apr 2016 14:48:05 +0200 Subject: serial: tegra: Remove unused variable The local mcr variable is never used in the tegra_uart_set_mctrl() function, so it should be removed. Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial-tegra.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 1d6fc60..1dba671 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -206,10 +206,8 @@ static void set_dtr(struct tegra_uart_port *tup, bool active) static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl) { struct tegra_uart_port *tup = to_tegra_uport(u); - unsigned long mcr; int dtr_enable; - mcr = tup->mcr_shadow; tup->rts_active = !!(mctrl & TIOCM_RTS); set_rts(tup, tup->rts_active); -- cgit v1.1 From ec5a11a91eecd81ef19b8044a243b4ea56c809e6 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 22:14:32 -0700 Subject: serial: 8250: Validate dmaengine rx chan meets requirements 8250 dma support requires the dmaengine driver support error-free pause/terminate and better-than-descriptor residue granularity. Query slave caps to determine if necessary commands/properties are supported; disable dma if not. Note this means dmaengine driver must support slave caps reporting as well. Signed-off-by: Peter Hurley Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dma.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 78259d3..cf7a2e3 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -158,6 +158,8 @@ int serial8250_request_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; dma_cap_mask_t mask; + struct dma_slave_caps caps; + int ret; /* Default slave configuration parameters */ dma->rxconf.direction = DMA_DEV_TO_MEM; @@ -178,6 +180,16 @@ int serial8250_request_dma(struct uart_8250_port *p) if (!dma->rxchan) return -ENODEV; + /* 8250 rx dma requires dmaengine driver to support pause/terminate */ + ret = dma_get_slave_caps(dma->rxchan, &caps); + if (ret) + goto release_rx; + if (!caps.cmd_pause || !caps.cmd_terminate || + caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) { + ret = -EINVAL; + goto release_rx; + } + dmaengine_slave_config(dma->rxchan, &dma->rxconf); /* Get a channel for TX */ @@ -185,8 +197,8 @@ int serial8250_request_dma(struct uart_8250_port *p) dma->fn, dma->tx_param, p->port.dev, "tx"); if (!dma->txchan) { - dma_release_channel(dma->rxchan); - return -ENODEV; + ret = -ENODEV; + goto release_rx; } dmaengine_slave_config(dma->txchan, &dma->txconf); @@ -197,8 +209,10 @@ int serial8250_request_dma(struct uart_8250_port *p) dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size, &dma->rx_addr, GFP_KERNEL); - if (!dma->rx_buf) + if (!dma->rx_buf) { + ret = -ENOMEM; goto err; + } /* TX buffer */ dma->tx_addr = dma_map_single(dma->txchan->device->dev, @@ -208,6 +222,7 @@ int serial8250_request_dma(struct uart_8250_port *p) if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) { dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf, dma->rx_addr); + ret = -ENOMEM; goto err; } @@ -215,10 +230,10 @@ int serial8250_request_dma(struct uart_8250_port *p) return 0; err: - dma_release_channel(dma->rxchan); dma_release_channel(dma->txchan); - - return -ENOMEM; +release_rx: + dma_release_channel(dma->rxchan); + return ret; } EXPORT_SYMBOL_GPL(serial8250_request_dma); -- cgit v1.1 From ddedfd82bc61c8d8d4d0eb754a9bcebb2e84de75 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 22:14:33 -0700 Subject: serial: 8250: Validate dmaengine tx chan meets requirements 8250 dma support requires the dmaegine driver support terminate. Query slave caps to determine if necessary commands/properties are supported; disable dma if not. Note this means dmaengine driver must support slave caps reporting as well. Signed-off-by: Peter Hurley Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dma.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index cf7a2e3..7a26c4d 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -201,6 +201,15 @@ int serial8250_request_dma(struct uart_8250_port *p) goto release_rx; } + /* 8250 tx dma requires dmaengine driver to support terminate */ + ret = dma_get_slave_caps(dma->txchan, &caps); + if (ret) + goto err; + if (!caps.cmd_terminate) { + ret = -EINVAL; + goto err; + } + dmaengine_slave_config(dma->txchan, &dma->txconf); /* RX buffer */ -- cgit v1.1 From ed183ee689058775b24021272c3a01d356fe8e2e Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 22:14:34 -0700 Subject: serial: omap8250: Drop rx buffer sync commit 27c310c5c312 ("serial: 8250_dma: no need to sync RX buffer") notes the RX DMA buffer is allocated from DMA coherent memory, and thus does not need sync'd for each transaction. The same is true for OMAP RX DMA. Signed-off-by: Peter Hurley Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index abeaf5e..ca2a850 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -754,9 +754,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) unsigned long flags; int ret; - 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) @@ -868,9 +865,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) dma->rx_cookie = dmaengine_submit(desc); - dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr, - dma->rx_size, DMA_FROM_DEVICE); - dma_async_issue_pending(dma->rxchan); out: spin_unlock_irqrestore(&priv->rx_dma_lock, flags); -- cgit v1.1 From b74fdd23d8fb4e349185ed9d963da8fc2b6eb34c Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 22:14:35 -0700 Subject: serial: omap8250: Simplify rx dma completion interface Extract the operation (restarting new rx dma) performed when error argument is true. Signed-off-by: Peter Hurley Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index ca2a850..27702d5 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -744,7 +744,7 @@ static void omap_8250_unthrottle(struct uart_port *port) #ifdef CONFIG_SERIAL_8250_DMA static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir); -static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) +static void __dma_rx_do_complete(struct uart_8250_port *p) { struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; @@ -772,15 +772,13 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) unlock: spin_unlock_irqrestore(&priv->rx_dma_lock, flags); - if (!error) - omap_8250_rx_dma(p, 0); - tty_flip_buffer_push(tty_port); } static void __dma_rx_complete(void *param) { - __dma_rx_do_complete(param, false); + __dma_rx_do_complete(param); + omap_8250_rx_dma(param, 0); } static void omap_8250_rx_dma_flush(struct uart_8250_port *p) @@ -803,7 +801,7 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p) spin_unlock_irqrestore(&priv->rx_dma_lock, flags); - __dma_rx_do_complete(p, true); + __dma_rx_do_complete(p); } static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) -- cgit v1.1 From 33d9b8b23a73d5d8609a740d0adeea8235c2ae52 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 22:14:36 -0700 Subject: serial: 8250: Extract IIR logic steering from rx dma Using fake IIR values to perform rx dma operations unnecessarily conflates separate operations, stopping in-progress dma with starting new dma. Introduce serial8250_rx_dma_flush() to handle stopping in-progress dma [omap8250 already has equivalent omap_8250_rx_dma_flush()]. Replace rx_dma(UART_IIR_RX_TIMEOUT) with the equivalent *_rx_dma_flush(), and rx_dma(0) with the equivalent *_rx_dma(). Handle IIR steering in the irq handler with handle_rx_dma() helper. Signed-off-by: Peter Hurley Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 8 +++-- drivers/tty/serial/8250/8250_dma.c | 32 +++++++----------- drivers/tty/serial/8250/8250_omap.c | 67 ++++++++++++++++--------------------- drivers/tty/serial/8250/8250_port.c | 14 +++++++- 4 files changed, 58 insertions(+), 63 deletions(-) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 8739d22..7a4c826 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -17,7 +17,7 @@ struct uart_8250_dma { int (*tx_dma)(struct uart_8250_port *p); - int (*rx_dma)(struct uart_8250_port *p, unsigned int iir); + int (*rx_dma)(struct uart_8250_port *p); /* Filter function */ dma_filter_fn fn; @@ -189,7 +189,8 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt) #ifdef CONFIG_SERIAL_8250_DMA extern int serial8250_tx_dma(struct uart_8250_port *); -extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir); +extern int serial8250_rx_dma(struct uart_8250_port *); +extern void serial8250_rx_dma_flush(struct uart_8250_port *); extern int serial8250_request_dma(struct uart_8250_port *); extern void serial8250_release_dma(struct uart_8250_port *); #else @@ -197,10 +198,11 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p) { return -1; } -static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +static inline int serial8250_rx_dma(struct uart_8250_port *p) { return -1; } +static inline void serial8250_rx_dma_flush(struct uart_8250_port *p) { } static inline int serial8250_request_dma(struct uart_8250_port *p) { return -1; diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 7a26c4d..7f33d1c 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -110,30 +110,11 @@ err: return ret; } -int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +int serial8250_rx_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; struct dma_async_tx_descriptor *desc; - switch (iir & 0x3f) { - case UART_IIR_RLSI: - /* 8250_core handles errors and break interrupts */ - 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_complete(p); - dmaengine_terminate_all(dma->rxchan); - } - return -ETIMEDOUT; - default: - break; - } - if (dma->rx_running) return 0; @@ -154,6 +135,17 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) return 0; } +void serial8250_rx_dma_flush(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + if (dma->rx_running) { + dmaengine_pause(dma->rxchan); + __dma_rx_complete(p); + dmaengine_terminate_all(dma->rxchan); + } +} + int serial8250_request_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 27702d5..8579b0c 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -115,6 +115,12 @@ struct omap8250_priv { bool rx_dma_broken; }; +#ifdef CONFIG_SERIAL_8250_DMA +static void omap_8250_rx_dma_flush(struct uart_8250_port *p); +#else +static inline void omap_8250_rx_dma_flush(struct uart_8250_port *p) { } +#endif + static u32 uart_read(struct uart_8250_port *up, u32 reg) { return readl(up->port.membase + (reg << up->port.regshift)); @@ -635,7 +641,7 @@ static int omap_8250_startup(struct uart_port *port) serial_out(up, UART_OMAP_WER, priv->wer); if (up->dma) - up->dma->rx_dma(up, 0); + up->dma->rx_dma(up); pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); @@ -654,7 +660,7 @@ static void omap_8250_shutdown(struct uart_port *port) flush_work(&priv->qos_work); if (up->dma) - up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT); + omap_8250_rx_dma_flush(up); pm_runtime_get_sync(port->dev); @@ -742,7 +748,7 @@ static void omap_8250_unthrottle(struct uart_port *port) } #ifdef CONFIG_SERIAL_8250_DMA -static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir); +static int omap_8250_rx_dma(struct uart_8250_port *p); static void __dma_rx_do_complete(struct uart_8250_port *p) { @@ -778,7 +784,7 @@ unlock: static void __dma_rx_complete(void *param) { __dma_rx_do_complete(param); - omap_8250_rx_dma(param, 0); + omap_8250_rx_dma(param); } static void omap_8250_rx_dma_flush(struct uart_8250_port *p) @@ -804,7 +810,7 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p) __dma_rx_do_complete(p); } -static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +static int omap_8250_rx_dma(struct uart_8250_port *p) { struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; @@ -812,35 +818,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) struct dma_async_tx_descriptor *desc; unsigned long flags; - switch (iir & 0x3f) { - case UART_IIR_RLSI: - /* 8250_core handles errors and break interrupts */ - 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. - */ - omap_8250_rx_dma_flush(p); - return -ETIMEDOUT; - case UART_IIR_RDI: - /* - * The OMAP UART is a special BEAST. If we receive RDI we _have_ - * a DMA transfer programmed but it didn't work. One reason is - * that we were too slow and there were too many bytes in the - * FIFO, the UART counted wrong and never kicked the DMA engine - * to do anything. That means once we receive RDI on OMAP then - * the DMA won't do anything soon so we have to cancel the DMA - * transfer and purge the FIFO manually. - */ - omap_8250_rx_dma_flush(p); - return -ETIMEDOUT; - - default: - break; - } - if (priv->rx_dma_broken) return -EINVAL; @@ -1014,6 +991,18 @@ err: return ret; } +static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) +{ + switch (iir & 0x3f) { + case UART_IIR_RLSI: + case UART_IIR_RX_TIMEOUT: + case UART_IIR_RDI: + omap_8250_rx_dma_flush(up); + return true; + } + return omap_8250_rx_dma(up); +} + /* * This is mostly serial8250_handle_irq(). We have a slightly different DMA * hoook for RX/TX and need different logic for them in the ISR. Therefore we @@ -1039,9 +1028,9 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) status = serial_port_in(port, UART_LSR); if (status & (UART_LSR_DR | UART_LSR_BI)) { - if (omap_8250_rx_dma(up, iir)) { + if (handle_rx_dma(up, iir)) { status = serial8250_rx_chars(up, status); - omap_8250_rx_dma(up, 0); + omap_8250_rx_dma(up); } } serial8250_modem_status(up); @@ -1072,7 +1061,7 @@ static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param) #else -static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +static inline int omap_8250_rx_dma(struct uart_8250_port *p) { return -EINVAL; } @@ -1383,7 +1372,7 @@ static int omap8250_runtime_suspend(struct device *dev) } if (up->dma && up->dma->rxchan) - omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); + omap_8250_rx_dma_flush(up); priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; schedule_work(&priv->qos_work); @@ -1406,7 +1395,7 @@ static int omap8250_runtime_resume(struct device *dev) omap8250_restore_regs(up); if (up->dma && up->dma->rxchan) - omap_8250_rx_dma(up, 0); + omap_8250_rx_dma(up); priv->latency = priv->calc_latency; schedule_work(&priv->qos_work); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index b2bbb9d..215e8da 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1788,6 +1788,18 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up) } EXPORT_SYMBOL_GPL(serial8250_modem_status); +static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) +{ + switch (iir & 0x3f) { + case UART_IIR_RX_TIMEOUT: + serial8250_rx_dma_flush(up); + /* fall-through */ + case UART_IIR_RLSI: + return true; + } + return up->dma->rx_dma(up); +} + /* * This handles the interrupt from one port. */ @@ -1807,7 +1819,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) DEBUG_INTR("status = %x...", status); if (status & (UART_LSR_DR | UART_LSR_BI)) { - if (!up->dma || up->dma->rx_dma(up, iir)) + if (!up->dma || handle_rx_dma(up, iir)) status = serial8250_rx_chars(up, status); } serial8250_modem_status(up); -- cgit v1.1 From d1f981506b38933e9ba4cfe01ae98bcd5d3792f9 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Apr 2016 22:14:37 -0700 Subject: serial: omap8250: Terminate rx dma only for flushes DMA completed normally does not require termination; only terminate paused rx dma stemming from rx dma flush. Signed-off-by: Peter Hurley Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 8579b0c..2c44c79 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -767,7 +767,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) dma->rx_running = 0; dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); - dmaengine_terminate_all(dma->rxchan); count = dma->rx_size - state.residue; @@ -808,6 +807,7 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p) spin_unlock_irqrestore(&priv->rx_dma_lock, flags); __dma_rx_do_complete(p); + dmaengine_terminate_all(dma->rxchan); } static int omap_8250_rx_dma(struct uart_8250_port *p) -- cgit v1.1 From 28264eb6c36e267aad0e6cfb353ad1e7920ac87b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 28 Apr 2016 14:47:24 +0200 Subject: serial: 8250: of: Make tegra_serial_handle_break() static This function is not used outside the file, so it can be static. Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index c7ed3d2b..38963d7 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -29,7 +29,7 @@ struct of_serial_info { }; #ifdef CONFIG_ARCH_TEGRA -void tegra_serial_handle_break(struct uart_port *p) +static void tegra_serial_handle_break(struct uart_port *p) { unsigned int status, tmout = 10000; -- cgit v1.1 From 8d21f24416719198c860009210a5fa9b33487211 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 17:22:20 +0200 Subject: doc: DT: Add Generic Serial Device Tree Bindings Document a set of generic properties for describing UARTs in a device tree: 1. The GPIO modem control properties are currently duplicated across hardware-specific binding documentation, 2. The property for dedicated RTS/CTS hardware flow control lines is already supported by several drivers, albeit with a vendor-specific prefix, hence make it generic. Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/serial.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/serial.txt diff --git a/Documentation/devicetree/bindings/serial/serial.txt b/Documentation/devicetree/bindings/serial/serial.txt new file mode 100644 index 0000000..fd970f7 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/serial.txt @@ -0,0 +1,57 @@ +Generic Serial DT Bindings + +This document lists a set of generic properties for describing UARTs in a +device tree. Whether these properties apply to a particular device depends on +the DT bindings for the actual device. + +Optional properties: + - cts-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's CTS line. + - dcd-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's DCD line. + - dsr-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's DSR line. + - dtr-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's DTR line. + - rng-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's RNG line. + - rts-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's RTS line. + + - uart-has-rtscts: The presence of this property indicates that the + UART has dedicated lines for RTS/CTS hardware flow control, and that + they are available for use (wired and enabled by pinmux configuration). + This depends on both the UART hardware and the board wiring. + Note that this property is mutually-exclusive with "cts-gpios" and + "rts-gpios" above. + + +Examples: + + uart1: serial@48022000 { + compatible = "ti,am3352-uart", "ti,omap3-uart"; + ti,hwmods = "uart2"; + clock-frequency = <48000000>; + reg = <0x48022000 0x2000>; + interrupts = <73>; + dmas = <&edma 28 0>, <&edma 29 0>; + dma-names = "tx", "rx"; + dtr-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>; + dsr-gpios = <&gpio2 23 GPIO_ACTIVE_LOW>; + dcd-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>; + rng-gpios = <&gpio2 25 GPIO_ACTIVE_LOW>; + cts-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + rts-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + status = "okay"; + }; + + scifa4: serial@e6c80000 { + compatible = "renesas,scifa-sh73a0", "renesas,scifa"; + reg = <0xe6c80000 0x100>; + interrupts = ; + clocks = <&mstp2_clks SH73A0_CLK_SCIFA4>; + clock-names = "fck"; + power-domains = <&pd_a3sp>; + uart-has-rtscts; + status = "okay"; + }; -- cgit v1.1 From 1006ed7e1b258dac3e85c9fafe9d38b6020c917f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 17:22:21 +0200 Subject: serial: imx: Use generic uart-has-rtscts DT property Convert the Freescale IMX UART driver from using the vendor-specific "fsl,uart-has-rtscts" to the generic "uart-has-rtscts" DT property, as documented by the Generic Serial DT Bindings. The old vendor-specific property is still recognized by the driver for backwards compatibility, but deprecated. Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/fsl-imx-uart.txt | 4 ++-- drivers/tty/serial/imx.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt index ed94c21..1e82802 100644 --- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt @@ -6,7 +6,7 @@ Required properties: - interrupts : Should contain uart interrupt Optional properties: -- fsl,uart-has-rtscts : Indicate the uart has rts and cts +- uart-has-rtscts : Indicate the uart has rts and cts - fsl,irda-mode : Indicate the uart supports irda mode - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works in DCE mode by default. @@ -24,6 +24,6 @@ uart1: serial@73fbc000 { compatible = "fsl,imx51-uart", "fsl,imx21-uart"; reg = <0x73fbc000 0x4000>; interrupts = <31>; - fsl,uart-has-rtscts; + uart-has-rtscts; fsl,dte-mode; }; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 4b38392..0df2b1c 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1980,7 +1980,8 @@ static int serial_imx_probe_dt(struct imx_port *sport, } sport->port.line = ret; - if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) + if (of_get_property(np, "uart-has-rtscts", NULL) || + of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */) sport->have_rtscts = 1; if (of_get_property(np, "fsl,dte-mode", NULL)) -- cgit v1.1 From 182cdcb8bb16e687dae9b03ac9ca9d80e873c076 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 17:22:22 +0200 Subject: serial: mxs-auart: Use generic uart-has-rtscts DT property Convert the Freescale MXS AUART driver from using the vendor-specific "fsl,uart-has-rtscts" to the generic "uart-has-rtscts" DT property, as documented by the Generic Serial DT Bindings. The old vendor-specific property is still recognized by the driver for backwards compatibility, but it is deprecated. Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt | 2 +- drivers/tty/serial/mxs-auart.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt index 81e35cd..5c96d41 100644 --- a/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt @@ -19,7 +19,7 @@ Required properties for "alphascale,asm9260-auart": "ahb" - ahb gate. Optional properties: -- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines +- uart-has-rtscts : Indicate the UART has RTS and CTS lines for hardware flow control, it also means you enable the DMA support for this UART. - {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 68a6e95..eb54e5c 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1570,7 +1570,8 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s, } s->port.line = ret; - if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) + if (of_get_property(np, "uart-has-rtscts", NULL) || + of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */) set_bit(MXS_AUART_RTSCTS, &s->flags); return 0; -- cgit v1.1 From af99c187f167a9498fd548b81ec78890ef86c170 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 17:22:23 +0200 Subject: serial: sirf: Introduce helper variable struct device_node *np Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sirfsoc_uart.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index c6657de..1d1c0b9 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -1264,6 +1264,7 @@ MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids); static int sirfsoc_uart_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct sirfsoc_uart_port *sirfport; struct uart_port *port; struct resource *res; @@ -1276,13 +1277,13 @@ 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); + match = of_match_node(sirfsoc_uart_ids, np); sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL); if (!sirfport) { ret = -ENOMEM; goto err; } - sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial"); + sirfport->port.line = of_alias_get_id(np, "serial"); sirf_ports[sirfport->port.line] = sirfport; sirfport->port.iotype = UPIO_MEM; sirfport->port.flags = UPF_BOOT_AUTOCONF; @@ -1291,25 +1292,24 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) port->private_data = sirfport; sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data; - sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node, - "sirf,uart-has-rtscts"); - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart") || - of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart")) + sirfport->hw_flow_ctrl = + of_property_read_bool(np, "sirf,uart-has-rtscts"); + if (of_device_is_compatible(np, "sirf,prima2-uart") || + of_device_is_compatible(np, "sirf,atlas7-uart")) sirfport->uart_reg->uart_type = SIRF_REAL_UART; - if (of_device_is_compatible(pdev->dev.of_node, - "sirf,prima2-usp-uart") || of_device_is_compatible( - pdev->dev.of_node, "sirf,atlas7-usp-uart")) { + if (of_device_is_compatible(np, "sirf,prima2-usp-uart") || + of_device_is_compatible(np, "sirf,atlas7-usp-uart")) { sirfport->uart_reg->uart_type = SIRF_USP_UART; if (!sirfport->hw_flow_ctrl) goto usp_no_flow_control; - if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL)) - sirfport->cts_gpio = of_get_named_gpio( - pdev->dev.of_node, "cts-gpios", 0); + if (of_find_property(np, "cts-gpios", NULL)) + sirfport->cts_gpio = + of_get_named_gpio(np, "cts-gpios", 0); else sirfport->cts_gpio = -1; - if (of_find_property(pdev->dev.of_node, "rts-gpios", NULL)) - sirfport->rts_gpio = of_get_named_gpio( - pdev->dev.of_node, "rts-gpios", 0); + if (of_find_property(np, "rts-gpios", NULL)) + sirfport->rts_gpio = + of_get_named_gpio(np, "rts-gpios", 0); else sirfport->rts_gpio = -1; @@ -1336,13 +1336,11 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) gpio_direction_output(sirfport->rts_gpio, 1); } usp_no_flow_control: - if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") || - of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart")) + if (of_device_is_compatible(np, "sirf,atlas7-uart") || + of_device_is_compatible(np, "sirf,atlas7-usp-uart")) sirfport->is_atlas7 = true; - if (of_property_read_u32(pdev->dev.of_node, - "fifosize", - &port->fifosize)) { + if (of_property_read_u32(np, "fifosize", &port->fifosize)) { dev_err(&pdev->dev, "Unable to find fifosize in uart node.\n"); ret = -EFAULT; -- cgit v1.1 From 7f60830ab1511d9449ac60ba4591fe3730445587 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Apr 2016 17:22:24 +0200 Subject: serial: sirf: Use generic uart-has-rtscts DT property Convert the SiRF UART driver from using the vendor-specific "sirf,uart-has-rtscts" to the generic "uart-has-rtscts" DT property, as documented by the Generic Serial DT Bindings. The old vendor-specific property is still recognized by the driver for backwards compatibility, but deprecated. Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/sirf-uart.txt | 8 ++++---- drivers/tty/serial/sirfsoc_uart.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/sirf-uart.txt b/Documentation/devicetree/bindings/serial/sirf-uart.txt index 67e2a0a..1e48bbb 100644 --- a/Documentation/devicetree/bindings/serial/sirf-uart.txt +++ b/Documentation/devicetree/bindings/serial/sirf-uart.txt @@ -9,9 +9,9 @@ Required properties: - clocks : Should contain uart clock number Optional properties: -- sirf,uart-has-rtscts: we have hardware flow controller pins in hardware -- rts-gpios: RTS pin for USP-based UART if sirf,uart-has-rtscts is true -- cts-gpios: CTS pin for USP-based UART if sirf,uart-has-rtscts is true +- uart-has-rtscts: we have hardware flow controller pins in hardware +- rts-gpios: RTS pin for USP-based UART if uart-has-rtscts is true +- cts-gpios: CTS pin for USP-based UART if uart-has-rtscts is true Example: @@ -28,7 +28,7 @@ On the board-specific dts, we can put rts-gpios and cts-gpios like usp@b0090000 { compatible = "sirf,prima2-usp-uart"; - sirf,uart-has-rtscts; + uart-has-rtscts; rts-gpios = <&gpio 15 0>; cts-gpios = <&gpio 46 0>; }; diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 1d1c0b9..b186c9c 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -1293,7 +1293,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data; sirfport->hw_flow_ctrl = - of_property_read_bool(np, "sirf,uart-has-rtscts"); + of_property_read_bool(np, "uart-has-rtscts") || + of_property_read_bool(np, "sirf,uart-has-rtscts") /* deprecated */; if (of_device_is_compatible(np, "sirf,prima2-uart") || of_device_is_compatible(np, "sirf,atlas7-uart")) sirfport->uart_reg->uart_type = SIRF_REAL_UART; -- cgit v1.1 From 8a872e770f86568bd45e90bbdce24dead4ee844d Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Mon, 25 Apr 2016 09:47:46 +0100 Subject: dt-bindings: document the MPS2 UART bindings This adds documentation of device tree bindings for the UART found on ARM MPS2 platform Acked-by: Rob Herring Signed-off-by: Vladimir Murzin Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/arm,mps2-uart.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/arm,mps2-uart.txt diff --git a/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt b/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt new file mode 100644 index 0000000..128cc6a --- /dev/null +++ b/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt @@ -0,0 +1,19 @@ +ARM MPS2 UART + +Required properties: +- compatible : Should be "arm,mps2-uart" +- reg : Address and length of the register set +- interrupts : Reference to the UART RX, TX and overrun interrupts + +Required clocking property: +- clocks : The input clock of the UART + + +Examples: + +uart0: serial@40004000 { + compatible = "arm,mps2-uart"; + reg = <0x40004000 0x1000>; + interrupts = <0 1 12>; + clocks = <&sysclk>; +}; -- cgit v1.1 From 041f031def330582108bc37f97525d9e7c0e2b2f Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Mon, 25 Apr 2016 09:47:47 +0100 Subject: serial: mps2-uart: add MPS2 UART driver This driver adds support to the UART controller found on ARM MPS2 platform. Acked-by: Greg Kroah-Hartman Reviewed-by: Andy Shevchenko Signed-off-by: Vladimir Murzin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 12 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/mps2-uart.c | 597 +++++++++++++++++++++++++++++++++++++++ include/uapi/linux/serial_core.h | 3 + 4 files changed, 613 insertions(+) create mode 100644 drivers/tty/serial/mps2-uart.c diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 9af489b..3b0a9b3 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1448,6 +1448,18 @@ config SERIAL_EFM32_UART This driver support the USART and UART ports on Energy Micro's efm32 SoCs. +config SERIAL_MPS2_UART_CONSOLE + bool "MPS2 UART console support" + depends on SERIAL_MPS2_UART + select SERIAL_CORE_CONSOLE + +config SERIAL_MPS2_UART + bool "MPS2 UART port" + depends on ARM || COMPILE_TEST + select SERIAL_CORE + help + This driver support the UART ports on ARM MPS2. + config SERIAL_EFM32_UART_CONSOLE bool "EFM32 UART/USART console support" depends on SERIAL_EFM32_UART=y diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 8c261ad..81e9057 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o +obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c new file mode 100644 index 0000000..e571e4c --- /dev/null +++ b/drivers/tty/serial/mps2-uart.c @@ -0,0 +1,597 @@ +/* + * Copyright (C) 2015 ARM Limited + * + * Author: Vladimir Murzin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * TODO: support for SysRq + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SERIAL_NAME "ttyMPS" +#define DRIVER_NAME "mps2-uart" +#define MAKE_NAME(x) (DRIVER_NAME # x) + +#define UARTn_DATA 0x00 + +#define UARTn_STATE 0x04 +#define UARTn_STATE_TX_FULL BIT(0) +#define UARTn_STATE_RX_FULL BIT(1) +#define UARTn_STATE_TX_OVERRUN BIT(2) +#define UARTn_STATE_RX_OVERRUN BIT(3) + +#define UARTn_CTRL 0x08 +#define UARTn_CTRL_TX_ENABLE BIT(0) +#define UARTn_CTRL_RX_ENABLE BIT(1) +#define UARTn_CTRL_TX_INT_ENABLE BIT(2) +#define UARTn_CTRL_RX_INT_ENABLE BIT(3) +#define UARTn_CTRL_TX_OVERRUN_INT_ENABLE BIT(4) +#define UARTn_CTRL_RX_OVERRUN_INT_ENABLE BIT(5) + +#define UARTn_INT 0x0c +#define UARTn_INT_TX BIT(0) +#define UARTn_INT_RX BIT(1) +#define UARTn_INT_TX_OVERRUN BIT(2) +#define UARTn_INT_RX_OVERRUN BIT(3) + +#define UARTn_BAUDDIV 0x10 +#define UARTn_BAUDDIV_MASK GENMASK(20, 0) + +/* + * Helpers to make typical enable/disable operations more readable. + */ +#define UARTn_CTRL_TX_GRP (UARTn_CTRL_TX_ENABLE |\ + UARTn_CTRL_TX_INT_ENABLE |\ + UARTn_CTRL_TX_OVERRUN_INT_ENABLE) + +#define UARTn_CTRL_RX_GRP (UARTn_CTRL_RX_ENABLE |\ + UARTn_CTRL_RX_INT_ENABLE |\ + UARTn_CTRL_RX_OVERRUN_INT_ENABLE) + +#define MPS2_MAX_PORTS 3 + +struct mps2_uart_port { + struct uart_port port; + struct clk *clk; + unsigned int tx_irq; + unsigned int rx_irq; +}; + +static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port) +{ + return container_of(port, struct mps2_uart_port, port); +} + +static void mps2_uart_write8(struct uart_port *port, u8 val, unsigned int off) +{ + struct mps2_uart_port *mps_port = to_mps2_port(port); + + writeb(val, mps_port->port.membase + off); +} + +static u8 mps2_uart_read8(struct uart_port *port, unsigned int off) +{ + struct mps2_uart_port *mps_port = to_mps2_port(port); + + return readb(mps_port->port.membase + off); +} + +static void mps2_uart_write32(struct uart_port *port, u32 val, unsigned int off) +{ + struct mps2_uart_port *mps_port = to_mps2_port(port); + + writel_relaxed(val, mps_port->port.membase + off); +} + +static unsigned int mps2_uart_tx_empty(struct uart_port *port) +{ + u8 status = mps2_uart_read8(port, UARTn_STATE); + + return (status & UARTn_STATE_TX_FULL) ? 0 : TIOCSER_TEMT; +} + +static void mps2_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static unsigned int mps2_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR; +} + +static void mps2_uart_stop_tx(struct uart_port *port) +{ + u8 control = mps2_uart_read8(port, UARTn_CTRL); + + control &= ~UARTn_CTRL_TX_INT_ENABLE; + + mps2_uart_write8(port, control, UARTn_CTRL); +} + +static void mps2_uart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + while (!(mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)) { + if (port->x_char) { + mps2_uart_write8(port, port->x_char, UARTn_DATA); + port->x_char = 0; + port->icount.tx++; + continue; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + break; + + mps2_uart_write8(port, xmit->buf[xmit->tail], UARTn_DATA); + xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE; + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + mps2_uart_stop_tx(port); +} + +static void mps2_uart_start_tx(struct uart_port *port) +{ + u8 control = mps2_uart_read8(port, UARTn_CTRL); + + control |= UARTn_CTRL_TX_INT_ENABLE; + + mps2_uart_write8(port, control, UARTn_CTRL); + + /* + * We've just unmasked the TX IRQ and now slow-starting via + * polling; if there is enough data to fill up the internal + * write buffer in one go, the TX IRQ should assert, at which + * point we switch to fully interrupt-driven TX. + */ + + mps2_uart_tx_chars(port); +} + +static void mps2_uart_stop_rx(struct uart_port *port) +{ + u8 control = mps2_uart_read8(port, UARTn_CTRL); + + control &= ~UARTn_CTRL_RX_GRP; + + mps2_uart_write8(port, control, UARTn_CTRL); +} + +static void mps2_uart_break_ctl(struct uart_port *port, int ctl) +{ +} + +static void mps2_uart_rx_chars(struct uart_port *port) +{ + struct tty_port *tport = &port->state->port; + + while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_RX_FULL) { + u8 rxdata = mps2_uart_read8(port, UARTn_DATA); + + port->icount.rx++; + tty_insert_flip_char(&port->state->port, rxdata, TTY_NORMAL); + } + + tty_flip_buffer_push(tport); +} + +static irqreturn_t mps2_uart_rxirq(int irq, void *data) +{ + struct uart_port *port = data; + u8 irqflag = mps2_uart_read8(port, UARTn_INT); + + if (unlikely(!(irqflag & UARTn_INT_RX))) + return IRQ_NONE; + + spin_lock(&port->lock); + + mps2_uart_write8(port, UARTn_INT_RX, UARTn_INT); + mps2_uart_rx_chars(port); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t mps2_uart_txirq(int irq, void *data) +{ + struct uart_port *port = data; + u8 irqflag = mps2_uart_read8(port, UARTn_INT); + + if (unlikely(!(irqflag & UARTn_INT_TX))) + return IRQ_NONE; + + spin_lock(&port->lock); + + mps2_uart_write8(port, UARTn_INT_TX, UARTn_INT); + mps2_uart_tx_chars(port); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t mps2_uart_oerrirq(int irq, void *data) +{ + irqreturn_t handled = IRQ_NONE; + struct uart_port *port = data; + u8 irqflag = mps2_uart_read8(port, UARTn_INT); + + spin_lock(&port->lock); + + if (irqflag & UARTn_INT_RX_OVERRUN) { + struct tty_port *tport = &port->state->port; + + mps2_uart_write8(port, UARTn_INT_RX_OVERRUN, UARTn_INT); + port->icount.overrun++; + tty_insert_flip_char(tport, 0, TTY_OVERRUN); + tty_flip_buffer_push(tport); + handled = IRQ_HANDLED; + } + + /* + * It's never been seen in practice and it never *should* happen since + * we check if there is enough room in TX buffer before sending data. + * So we keep this check in case something suspicious has happened. + */ + if (irqflag & UARTn_INT_TX_OVERRUN) { + mps2_uart_write8(port, UARTn_INT_TX_OVERRUN, UARTn_INT); + handled = IRQ_HANDLED; + } + + spin_unlock(&port->lock); + + return handled; +} + +static int mps2_uart_startup(struct uart_port *port) +{ + struct mps2_uart_port *mps_port = to_mps2_port(port); + u8 control = mps2_uart_read8(port, UARTn_CTRL); + int ret; + + control &= ~(UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP); + + mps2_uart_write8(port, control, UARTn_CTRL); + + ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0, + MAKE_NAME(-rx), mps_port); + if (ret) { + dev_err(port->dev, "failed to register rxirq (%d)\n", ret); + return ret; + } + + ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0, + MAKE_NAME(-tx), mps_port); + if (ret) { + dev_err(port->dev, "failed to register txirq (%d)\n", ret); + goto err_free_rxirq; + } + + ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED, + MAKE_NAME(-overrun), mps_port); + + if (ret) { + dev_err(port->dev, "failed to register oerrirq (%d)\n", ret); + goto err_free_txirq; + } + + control |= UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP; + + mps2_uart_write8(port, control, UARTn_CTRL); + + return 0; + +err_free_txirq: + free_irq(mps_port->tx_irq, mps_port); +err_free_rxirq: + free_irq(mps_port->rx_irq, mps_port); + + return ret; +} + +static void mps2_uart_shutdown(struct uart_port *port) +{ + struct mps2_uart_port *mps_port = to_mps2_port(port); + u8 control = mps2_uart_read8(port, UARTn_CTRL); + + control &= ~(UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP); + + mps2_uart_write8(port, control, UARTn_CTRL); + + free_irq(mps_port->rx_irq, mps_port); + free_irq(mps_port->tx_irq, mps_port); + free_irq(port->irq, mps_port); +} + +static void +mps2_uart_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, bauddiv; + + termios->c_cflag &= ~(CRTSCTS | CMSPAR); + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + termios->c_cflag &= ~PARENB; + termios->c_cflag &= ~CSTOPB; + + baud = uart_get_baud_rate(port, termios, old, + DIV_ROUND_CLOSEST(port->uartclk, UARTn_BAUDDIV_MASK), + DIV_ROUND_CLOSEST(port->uartclk, 16)); + + bauddiv = DIV_ROUND_CLOSEST(port->uartclk, baud); + + spin_lock_irqsave(&port->lock, flags); + + uart_update_timeout(port, termios->c_cflag, baud); + mps2_uart_write32(port, bauddiv, UARTn_BAUDDIV); + + spin_unlock_irqrestore(&port->lock, flags); + + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} + +static const char *mps2_uart_type(struct uart_port *port) +{ + return (port->type == PORT_MPS2UART) ? DRIVER_NAME : NULL; +} + +static void mps2_uart_release_port(struct uart_port *port) +{ +} + +static int mps2_uart_request_port(struct uart_port *port) +{ + return 0; +} + +static void mps2_uart_config_port(struct uart_port *port, int type) +{ + if (type & UART_CONFIG_TYPE && !mps2_uart_request_port(port)) + port->type = PORT_MPS2UART; +} + +static int mps2_uart_verify_port(struct uart_port *port, struct serial_struct *serinfo) +{ + return -EINVAL; +} + +static const struct uart_ops mps2_uart_pops = { + .tx_empty = mps2_uart_tx_empty, + .set_mctrl = mps2_uart_set_mctrl, + .get_mctrl = mps2_uart_get_mctrl, + .stop_tx = mps2_uart_stop_tx, + .start_tx = mps2_uart_start_tx, + .stop_rx = mps2_uart_stop_rx, + .break_ctl = mps2_uart_break_ctl, + .startup = mps2_uart_startup, + .shutdown = mps2_uart_shutdown, + .set_termios = mps2_uart_set_termios, + .type = mps2_uart_type, + .release_port = mps2_uart_release_port, + .request_port = mps2_uart_request_port, + .config_port = mps2_uart_config_port, + .verify_port = mps2_uart_verify_port, +}; + +static struct mps2_uart_port mps2_uart_ports[MPS2_MAX_PORTS]; + +#ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE +static void mps2_uart_console_putchar(struct uart_port *port, int ch) +{ + while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL) + cpu_relax(); + + mps2_uart_write8(port, ch, UARTn_DATA); +} + +static void mps2_uart_console_write(struct console *co, const char *s, unsigned int cnt) +{ + struct uart_port *port = &mps2_uart_ports[co->index].port; + + uart_console_write(port, s, cnt, mps2_uart_console_putchar); +} + +static int mps2_uart_console_setup(struct console *co, char *options) +{ + struct mps2_uart_port *mps_port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= MPS2_MAX_PORTS) + return -ENODEV; + + mps_port = &mps2_uart_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&mps_port->port, co, baud, parity, bits, flow); +} + +static struct uart_driver mps2_uart_driver; + +static struct console mps2_uart_console = { + .name = SERIAL_NAME, + .device = uart_console_device, + .write = mps2_uart_console_write, + .setup = mps2_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &mps2_uart_driver, +}; + +#define MPS2_SERIAL_CONSOLE (&mps2_uart_console) + +#else +#define MPS2_SERIAL_CONSOLE NULL +#endif + +static struct uart_driver mps2_uart_driver = { + .driver_name = DRIVER_NAME, + .dev_name = SERIAL_NAME, + .nr = MPS2_MAX_PORTS, + .cons = MPS2_SERIAL_CONSOLE, +}; + +static struct mps2_uart_port *mps2_of_get_port(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int id; + + if (!np) + return NULL; + + id = of_alias_get_id(np, "serial"); + if (id < 0) + id = 0; + + if (WARN_ON(id >= MPS2_MAX_PORTS)) + return NULL; + + mps2_uart_ports[id].port.line = id; + return &mps2_uart_ports[id]; +} + +static int mps2_init_port(struct mps2_uart_port *mps_port, + struct platform_device *pdev) +{ + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mps_port->port.membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mps_port->port.membase)) + return PTR_ERR(mps_port->port.membase); + + mps_port->port.mapbase = res->start; + mps_port->port.mapsize = resource_size(res); + + mps_port->rx_irq = platform_get_irq(pdev, 0); + mps_port->tx_irq = platform_get_irq(pdev, 1); + mps_port->port.irq = platform_get_irq(pdev, 2); + + mps_port->port.iotype = UPIO_MEM; + mps_port->port.flags = UPF_BOOT_AUTOCONF; + mps_port->port.fifosize = 1; + mps_port->port.ops = &mps2_uart_pops; + mps_port->port.dev = &pdev->dev; + + mps_port->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(mps_port->clk)) + return PTR_ERR(mps_port->clk); + + ret = clk_prepare_enable(mps_port->clk); + if (ret) + return ret; + + mps_port->port.uartclk = clk_get_rate(mps_port->clk); + + clk_disable_unprepare(mps_port->clk); + + return ret; +} + +static int mps2_serial_probe(struct platform_device *pdev) +{ + struct mps2_uart_port *mps_port; + int ret; + + mps_port = mps2_of_get_port(pdev); + if (!mps_port) + return -ENODEV; + + ret = mps2_init_port(mps_port, pdev); + if (ret) + return ret; + + ret = uart_add_one_port(&mps2_uart_driver, &mps_port->port); + if (ret) + return ret; + + platform_set_drvdata(pdev, mps_port); + + return 0; +} + +static int mps2_serial_remove(struct platform_device *pdev) +{ + struct mps2_uart_port *mps_port = platform_get_drvdata(pdev); + + uart_remove_one_port(&mps2_uart_driver, &mps_port->port); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id mps2_match[] = { + { .compatible = "arm,mps2-uart", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mps2_match); +#endif + +static struct platform_driver mps2_serial_driver = { + .probe = mps2_serial_probe, + .remove = mps2_serial_remove, + + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(mps2_match), + }, +}; + +static int __init mps2_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&mps2_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&mps2_serial_driver); + if (ret) + uart_unregister_driver(&mps2_uart_driver); + + return ret; +} +module_init(mps2_uart_init); + +static void __exit mps2_uart_exit(void) +{ + platform_driver_unregister(&mps2_serial_driver); + uart_unregister_driver(&mps2_uart_driver); +} +module_exit(mps2_uart_exit); + +MODULE_AUTHOR("Vladimir Murzin "); +MODULE_DESCRIPTION("MPS2 UART driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index e513a4e..9aef04c 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -264,4 +264,7 @@ /* MVEBU UART */ #define PORT_MVEBU 114 +/* MPS2 UART */ +#define PORT_MPS2UART 115 + #endif /* _UAPILINUX_SERIAL_CORE_H */ -- cgit v1.1 From bd8d257fa3371a284568b8ee04c2bcf4757238ed Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Mon, 25 Apr 2016 09:47:48 +0100 Subject: serial: mps2-uart: add support for early console This adds support early console for MPS2 UART which can be enabled via earlycon=mps2,0x40004000 Acked-by: Greg Kroah-Hartman Reviewed-by: Peter Hurley Signed-off-by: Vladimir Murzin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/mps2-uart.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 3b0a9b3..331638d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1452,6 +1452,7 @@ config SERIAL_MPS2_UART_CONSOLE bool "MPS2 UART console support" depends on SERIAL_MPS2_UART select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON config SERIAL_MPS2_UART bool "MPS2 UART port" diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c index e571e4c..da9e27d 100644 --- a/drivers/tty/serial/mps2-uart.c +++ b/drivers/tty/serial/mps2-uart.c @@ -450,6 +450,34 @@ static struct console mps2_uart_console = { #define MPS2_SERIAL_CONSOLE (&mps2_uart_console) +static void mps2_early_putchar(struct uart_port *port, int ch) +{ + while (readb(port->membase + UARTn_STATE) & UARTn_STATE_TX_FULL) + cpu_relax(); + + writeb((unsigned char)ch, port->membase + UARTn_DATA); +} + +static void mps2_early_write(struct console *con, const char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, mps2_early_putchar); +} + +static int __init mps2_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = mps2_early_write; + + return 0; +} + +OF_EARLYCON_DECLARE(mps2, "arm,mps2-uart", mps2_early_console_setup); + #else #define MPS2_SERIAL_CONSOLE NULL #endif -- cgit v1.1 From fa01e2ca9f531b4a5693469a196eb1574b8d7d8a Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 27 Apr 2016 10:40:10 +0200 Subject: serial: 8250: Integrate Fintek into 8250_base The 8250_fintek driver advertises as the PNP0501 driver; however this conflicts with the standard 16550A uart PNP0501. The conflict causes the 8250_fintek driver to load with _every_ PNP0501, but never probe, and causing the entire 8250 driver stack to unload if the 8250_fintek driver is unloaded (modprobe doesn't know that 8250_pnp rather than 8250_fintek claimed the resource). This patch merges the Fintek driver into 8250_base. On autoconfig_16550 the device is probed to verify if it is a FINTEK device or not. This custom probing can be disabled completely via configuration. When a Fintek device is not probed it will behave as a standard 16550A device, with no RS485 capabilities. Reported-by: Peter Hurley Signed-off-by: Ricardo Ribalda Delgado Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 6 ++ drivers/tty/serial/8250/8250_fintek.c | 118 +++++----------------------------- drivers/tty/serial/8250/8250_port.c | 7 ++ drivers/tty/serial/8250/Kconfig | 20 +++--- drivers/tty/serial/8250/Makefile | 2 +- 5 files changed, 42 insertions(+), 111 deletions(-) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 7a4c826..215a992 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -150,6 +150,12 @@ static inline int serial8250_pnp_init(void) { return 0; } static inline void serial8250_pnp_exit(void) { } #endif +#ifdef CONFIG_SERIAL_8250_FINTEK +int fintek_8250_probe(struct uart_8250_port *uart); +#else +static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; } +#endif + #ifdef CONFIG_ARCH_OMAP1 static inline int is_omap1_8250(struct uart_8250_port *pt) { diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 8947439..870981d 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -1,9 +1,7 @@ /* * Probe for F81216A LPC to 4 UART * - * Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al - * - * Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S + * Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S * * * This program is free software; you can redistribute it and/or modify @@ -38,19 +36,15 @@ #define RXW4C_IRA BIT(3) #define TXW4C_IRA BIT(2) -#define DRIVER_NAME "8250_fintek" - struct fintek_8250 { u16 base_port; u8 index; u8 key; - long line; }; static int fintek_8250_enter_key(u16 base_port, u8 key) { - - if (!request_muxed_region(base_port, 2, DRIVER_NAME)) + if (!request_muxed_region(base_port, 2, "8250_fintek")) return -EBUSY; outb(key, base_port + ADDR_PORT); @@ -138,7 +132,7 @@ static int fintek_8250_rs485_config(struct uart_port *port, return 0; } -static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index) +static int find_base_port(struct fintek_8250 *pdata, u16 io_address) { static const u16 addr[] = {0x4e, 0x2e}; static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67}; @@ -168,10 +162,13 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index) continue; fintek_8250_exit_key(addr[i]); - *key = keys[j]; - *index = k; - return addr[i]; + pdata->key = keys[j]; + pdata->base_port = addr[i]; + pdata->index = k; + + return 0; } + fintek_8250_exit_key(addr[i]); } } @@ -179,104 +176,21 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index) return -ENODEV; } -static int -fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) +int fintek_8250_probe(struct uart_8250_port *uart) { - struct uart_8250_port uart; struct fintek_8250 *pdata; - int base_port; - u8 key; - u8 index; - - if (!pnp_port_valid(dev, 0)) - return -ENODEV; + struct fintek_8250 probe_data; - base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index); - if (base_port < 0) + if (find_base_port(&probe_data, uart->port.iobase)) return -ENODEV; - memset(&uart, 0, sizeof(uart)); - - pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - uart.port.private_data = pdata; - if (!pnp_irq_valid(dev, 0)) - return -ENODEV; - uart.port.irq = pnp_irq(dev, 0); - uart.port.iobase = pnp_port_start(dev, 0); - uart.port.iotype = UPIO_PORT; - uart.port.rs485_config = fintek_8250_rs485_config; - - uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; - if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE) - uart.port.flags |= UPF_SHARE_IRQ; - uart.port.uartclk = 1843200; - uart.port.dev = &dev->dev; - - pdata->key = key; - pdata->base_port = base_port; - pdata->index = index; - pdata->line = serial8250_register_8250_port(&uart); - if (pdata->line < 0) - return -ENODEV; + memcpy(pdata, &probe_data, sizeof(probe_data)); + uart->port.rs485_config = fintek_8250_rs485_config; + uart->port.private_data = pdata; - pnp_set_drvdata(dev, pdata); return 0; } - -static void fintek_8250_remove(struct pnp_dev *dev) -{ - struct fintek_8250 *pdata = pnp_get_drvdata(dev); - - if (pdata) - serial8250_unregister_port(pdata->line); -} - -#ifdef CONFIG_PM -static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state) -{ - struct fintek_8250 *pdata = pnp_get_drvdata(dev); - - if (!pdata) - return -ENODEV; - serial8250_suspend_port(pdata->line); - return 0; -} - -static int fintek_8250_resume(struct pnp_dev *dev) -{ - struct fintek_8250 *pdata = pnp_get_drvdata(dev); - - if (!pdata) - return -ENODEV; - serial8250_resume_port(pdata->line); - return 0; -} -#else -#define fintek_8250_suspend NULL -#define fintek_8250_resume NULL -#endif /* CONFIG_PM */ - -static const struct pnp_device_id fintek_dev_table[] = { - /* Qtechnology Panel PC / IO1000 */ - { "PNP0501"}, - {} -}; - -MODULE_DEVICE_TABLE(pnp, fintek_dev_table); - -static struct pnp_driver fintek_8250_driver = { - .name = DRIVER_NAME, - .probe = fintek_8250_probe, - .remove = fintek_8250_remove, - .suspend = fintek_8250_suspend, - .resume = fintek_8250_resume, - .id_table = fintek_dev_table, -}; - -module_pnp_driver(fintek_8250_driver); -MODULE_DESCRIPTION("Fintek F812164 module"); -MODULE_AUTHOR("Ricardo Ribalda "); -MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 215e8da..d403603 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1315,6 +1315,13 @@ static void autoconfig(struct uart_8250_port *up) out_lock: spin_unlock_irqrestore(&port->lock, flags); + + /* + * Check if the device is a Fintek F81216A + */ + if (port->type == PORT_16550A) + fintek_8250_probe(up); + if (up->capabilities != old_capabilities) { pr_warn("ttyS%d: detected caps %08x should be %08x\n", serial_index(port), old_capabilities, diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 7f33d349..e46761d 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -57,6 +57,18 @@ config SERIAL_8250_PNP This builds standard PNP serial support. You may be able to disable this feature if you only need legacy serial support. +config SERIAL_8250_FINTEK + bool "Support for Fintek F81216A LPC to 4 UART RS485 API" + depends on SERIAL_8250 + ---help--- + Selecting this option will add support for the RS485 capabilities + of the Fintek F81216A LPC to 4 UART. + + If this option is not selected the device will be configured as a + standard 16550A serial port. + + If unsure, say N. + config SERIAL_8250_CONSOLE bool "Console on 8250/16550 and compatible serial port" depends on SERIAL_8250=y @@ -358,14 +370,6 @@ config SERIAL_8250_OMAP_TTYO_FIXUP not booting kernel because the serial console remains silent in case they forgot to update the command line. -config SERIAL_8250_FINTEK - tristate "Support for Fintek F81216A LPC to 4 UART" - depends on SERIAL_8250 && PNP - help - Selecting this option will add support for the Fintek F81216A - LPC to 4 UART. This device has some RS485 functionality not available - through the PNP driver. If unsure, say N. - config SERIAL_8250_LPC18XX tristate "NXP LPC18xx/43xx serial port support" depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST) diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index c9a2d6e..367d403 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o 8250_base-y := 8250_port.o 8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o +8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o @@ -23,7 +24,6 @@ obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o -obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o -- cgit v1.1 From d11df61853f1d45035b7f5a6702c9b48d5f09a49 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Fri, 29 Apr 2016 10:45:07 +0200 Subject: serial: mctrl_gpio: add IRQ locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uart_handle_cts_change should be called with port->lock held. And for this to be save you must also disable irqs. Acked-by: Uwe Kleine-König Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_mctrl_gpio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index 0214736..9e1086f 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -125,9 +125,12 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context) struct uart_port *port = gpios->port; u32 mctrl = gpios->mctrl_prev; u32 mctrl_diff; + unsigned long flags; mctrl_gpio_get(gpios, &mctrl); + spin_lock_irqsave(&port->lock, flags); + mctrl_diff = mctrl ^ gpios->mctrl_prev; gpios->mctrl_prev = mctrl; @@ -147,6 +150,8 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context) wake_up_interruptible(&port->state->port.delta_msr_wait); } + spin_unlock_irqrestore(&port->lock, flags); + return IRQ_HANDLED; } -- cgit v1.1 From 0f40fbbcc34e093255a2b2d70b6b0fb48c3f39aa Mon Sep 17 00:00:00 2001 From: Brian Bloniarz Date: Sun, 6 Mar 2016 13:16:30 -0800 Subject: Fix OpenSSH pty regression on close OpenSSH expects the (non-blocking) read() of pty master to return EAGAIN only if it has received all of the slave-side output after it has received SIGCHLD. This used to work on pre-3.12 kernels. This fix effectively forces non-blocking read() and poll() to block for parallel i/o to complete for all ttys. It also unwinds these changes: 1) f8747d4a466ab2cafe56112c51b3379f9fdb7a12 tty: Fix pty master read() after slave closes 2) 52bce7f8d4fc633c9a9d0646eef58ba6ae9a3b73 pty, n_tty: Simplify input processing on final close 3) 1a48632ffed61352a7810ce089dc5a8bcd505a60 pty: Fix input race when closing Inspired by analysis and patch from Marc Aurele La France Reported-by: Volth Reported-by: Marc Aurele La France BugLink: https://bugzilla.mindrot.org/show_bug.cgi?id=52 BugLink: https://bugzilla.mindrot.org/show_bug.cgi?id=2492 Signed-off-by: Brian Bloniarz Reviewed-by: Peter Hurley Cc: stable Signed-off-by: Greg Kroah-Hartman --- Documentation/serial/tty.txt | 3 -- drivers/tty/n_hdlc.c | 4 +-- drivers/tty/n_tty.c | 70 +++++++++++++++++++++----------------------- drivers/tty/pty.c | 4 +-- drivers/tty/tty_buffer.c | 34 ++++----------------- include/linux/tty.h | 2 +- 6 files changed, 43 insertions(+), 74 deletions(-) diff --git a/Documentation/serial/tty.txt b/Documentation/serial/tty.txt index 798cba8..b487809 100644 --- a/Documentation/serial/tty.txt +++ b/Documentation/serial/tty.txt @@ -210,9 +210,6 @@ TTY_IO_ERROR If set, causes all subsequent userspace read/write TTY_OTHER_CLOSED Device is a pty and the other side has closed. -TTY_OTHER_DONE Device is a pty and the other side has closed and - all pending input processing has been completed. - TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into smaller chunks. diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index bcaba17..a7fa016 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -599,7 +599,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, add_wait_queue(&tty->read_wait, &wait); for (;;) { - if (test_bit(TTY_OTHER_DONE, &tty->flags)) { + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { ret = -EIO; break; } @@ -827,7 +827,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, /* set bits for operations that won't block */ if (n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ - if (test_bit(TTY_OTHER_DONE, &tty->flags)) + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) mask |= POLLHUP; if (tty_hung_up_p(filp)) mask |= POLLHUP; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index fb76a7d..bdf0e6e 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1917,18 +1917,6 @@ static inline int input_available_p(struct tty_struct *tty, int poll) return ldata->commit_head - ldata->read_tail >= amt; } -static inline int check_other_done(struct tty_struct *tty) -{ - int done = test_bit(TTY_OTHER_DONE, &tty->flags); - if (done) { - /* paired with cmpxchg() in check_other_closed(); ensures - * read buffer head index is not stale - */ - smp_mb__after_atomic(); - } - return done; -} - /** * copy_from_read_buf - copy read data directly * @tty: terminal device @@ -2124,7 +2112,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, struct n_tty_data *ldata = tty->disc_data; unsigned char __user *b = buf; DEFINE_WAIT_FUNC(wait, woken_wake_function); - int c, done; + int c; int minimum, time; ssize_t retval = 0; long timeout; @@ -2183,32 +2171,35 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, break; } - done = check_other_done(tty); - if (!input_available_p(tty, 0)) { - if (done) { - retval = -EIO; - break; - } - if (tty_hung_up_p(file)) - break; - if (!timeout) - break; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } up_read(&tty->termios_rwsem); + tty_buffer_flush_work(tty->port); + down_read(&tty->termios_rwsem); + if (!input_available_p(tty, 0)) { + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + retval = -EIO; + break; + } + if (tty_hung_up_p(file)) + break; + if (!timeout) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + up_read(&tty->termios_rwsem); - timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, - timeout); + timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, + timeout); - down_read(&tty->termios_rwsem); - continue; + down_read(&tty->termios_rwsem); + continue; + } } if (ldata->icanon && !L_EXTPROC(tty)) { @@ -2386,12 +2377,17 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); - if (check_other_done(tty)) - mask |= POLLHUP; if (input_available_p(tty, 1)) mask |= POLLIN | POLLRDNORM; + else { + tty_buffer_flush_work(tty->port); + if (input_available_p(tty, 1)) + mask |= POLLIN | POLLRDNORM; + } if (tty->packet && tty->link->ctrl_status) mask |= POLLPRI | POLLIN | POLLRDNORM; + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + mask |= POLLHUP; if (tty_hung_up_p(file)) mask |= POLLHUP; if (tty->ops->write && !tty_is_writelocked(tty) && diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index a8a292f..ee0e847 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -59,7 +59,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) if (!tty->link) return; set_bit(TTY_OTHER_CLOSED, &tty->link->flags); - tty_flip_buffer_push(tty->link->port); + wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); @@ -247,9 +247,7 @@ static int pty_open(struct tty_struct *tty, struct file *filp) goto out; clear_bit(TTY_IO_ERROR, &tty->flags); - /* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */ clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); - clear_bit(TTY_OTHER_DONE, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); return 0; diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index a946e49..aa80dc9 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -37,29 +37,6 @@ #define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) -/* - * If all tty flip buffers have been processed by flush_to_ldisc() or - * dropped by tty_buffer_flush(), check if the linked pty has been closed. - * If so, wake the reader/poll to process - */ -static inline void check_other_closed(struct tty_struct *tty) -{ - unsigned long flags, old; - - /* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */ - for (flags = ACCESS_ONCE(tty->flags); - test_bit(TTY_OTHER_CLOSED, &flags); - ) { - old = flags; - __set_bit(TTY_OTHER_DONE, &flags); - flags = cmpxchg(&tty->flags, old, flags); - if (old == flags) { - wake_up_interruptible(&tty->read_wait); - break; - } - } -} - /** * tty_buffer_lock_exclusive - gain exclusive access to buffer * tty_buffer_unlock_exclusive - release exclusive access @@ -254,8 +231,6 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) if (ld && ld->ops->flush_buffer) ld->ops->flush_buffer(tty); - check_other_closed(tty); - atomic_dec(&buf->priority); mutex_unlock(&buf->lock); } @@ -522,10 +497,8 @@ static void flush_to_ldisc(struct work_struct *work) */ count = smp_load_acquire(&head->commit) - head->read; if (!count) { - if (next == NULL) { - check_other_closed(tty); + if (next == NULL) break; - } buf->head = next; tty_buffer_free(port, head); continue; @@ -614,3 +587,8 @@ bool tty_buffer_cancel_work(struct tty_port *port) { return cancel_work_sync(&port->buf.work); } + +void tty_buffer_flush_work(struct tty_port *port) +{ + flush_work(&port->buf.work); +} diff --git a/include/linux/tty.h b/include/linux/tty.h index bf1bcdb..d82bb92 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -351,7 +351,6 @@ struct tty_file_private { #define TTY_OTHER_CLOSED 2 /* Other side (if any) has closed */ #define TTY_EXCLUSIVE 3 /* Exclusive open mode */ #define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ -#define TTY_OTHER_DONE 6 /* Closed pty has completed input processing */ #define TTY_LDISC_OPEN 11 /* Line discipline is open */ #define TTY_PTY_LOCK 16 /* pty private */ #define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ @@ -480,6 +479,7 @@ extern void tty_buffer_init(struct tty_port *port); extern void tty_buffer_set_lock_subclass(struct tty_port *port); extern bool tty_buffer_restart_work(struct tty_port *port); extern bool tty_buffer_cancel_work(struct tty_port *port); +extern void tty_buffer_flush_work(struct tty_port *port); extern speed_t tty_termios_baud_rate(struct ktermios *termios); extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); extern void tty_termios_encode_baud_rate(struct ktermios *termios, -- cgit v1.1 From 204e986d917cfa9364f05c5e7e42394a80788115 Mon Sep 17 00:00:00 2001 From: Wang Hongcheng Date: Fri, 11 Mar 2016 09:40:11 +0800 Subject: serial: 8250dw: Add device HID for future AMD UART controller Add device HID AMDI0020 to match the AMD ACPI Vendor ID (AMDI) as registered in http://www.uefi.org/acpi_id_list, and the UART controller on future AMD paltform will use the HID instead of AMD0020. Signed-off-by: Wang Hongcheng Acked-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a3fb95d..5364de3 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -617,6 +617,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = { { "8086228A", 0 }, { "APMC0D08", 0}, { "AMD0020", 0 }, + { "AMDI0020", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); -- cgit v1.1 From b67fcbdc5618d9a3a2b7bb22f7299556852e851f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 29 Apr 2016 13:40:26 +0200 Subject: serial: mctrl_gpio: Drop support for out1-gpios and out2-gpios The OUT1 and OUT2 pins present on some legacy UARTs are basically GPIOs. It doesn't make much sense to emulate GPIOs using other GPIOs, hence drop support for that. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Reviewed-by: Richard Genoud Reviewed-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_mctrl_gpio.c | 2 -- drivers/tty/serial/serial_mctrl_gpio.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index 9e1086f..e8dd509 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -43,8 +43,6 @@ static const struct { { "rng", TIOCM_RNG, false, }, { "rts", TIOCM_RTS, true, }, { "dtr", TIOCM_DTR, true, }, - { "out1", TIOCM_OUT1, true, }, - { "out2", TIOCM_OUT2, true, }, }; void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index bcfad5d..332a33a 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -32,8 +32,6 @@ enum mctrl_gpio_idx { UART_GPIO_RI = UART_GPIO_RNG, UART_GPIO_RTS, UART_GPIO_DTR, - UART_GPIO_OUT1, - UART_GPIO_OUT2, UART_GPIO_MAX, }; -- cgit v1.1 From 11ca2b7ab432eb90906168c327733575e68d388f Mon Sep 17 00:00:00 2001 From: Zhao Qiang Date: Wed, 9 Mar 2016 09:48:11 +0800 Subject: QE-UART: add "fsl,t1040-ucc-uart" to of_device_id New bindings use "fsl,t1040-ucc-uart" as the compatible for qe-uart. So add it. Signed-off-by: Zhao Qiang Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ucc_uart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 1a7dc3c..481eb29 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1478,6 +1478,9 @@ static const struct of_device_id ucc_uart_match[] = { .type = "serial", .compatible = "ucc_uart", }, + { + .compatible = "fsl,t1040-ucc-uart", + }, {}, }; MODULE_DEVICE_TABLE(of, ucc_uart_match); -- cgit v1.1 From 6798df4c5fe0a7e6d2065cf79649a794e5ba7114 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 3 May 2016 17:05:54 +0200 Subject: tty: vt, return error when con_startup fails When csw->con_startup() fails in do_register_con_driver, we return no error (i.e. 0). This was changed back in 2006 by commit 3e795de763. Before that we used to return -ENODEV. So fix the return value to be -ENODEV in that case again. Fixes: 3e795de763 ("VT binding: Add binding/unbinding support for the VT console") Signed-off-by: Jiri Slaby Reported-by: "Dan Carpenter" Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 8f9f8ed..3ed1ae2 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3594,9 +3594,10 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) goto err; desc = csw->con_startup(); - - if (!desc) + if (!desc) { + retval = -ENODEV; goto err; + } retval = -EINVAL; -- cgit v1.1 From 96317e9e2a12d01eaaebf6b1e92b0f96c121e20a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 3 May 2016 17:05:55 +0200 Subject: tty: vt, finish looping on duplicate When the console is already registered, stop crawling the registered_con_driver array and return an error immediatelly. This makes the code more obvious. And we do not need to initialize retval anymore. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3ed1ae2..dc12532 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3575,7 +3575,7 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) struct module *owner = csw->owner; struct con_driver *con_driver; const char *desc; - int i, retval = 0; + int i, retval; WARN_CONSOLE_UNLOCKED(); @@ -3586,13 +3586,12 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) con_driver = ®istered_con_driver[i]; /* already registered */ - if (con_driver->con == csw) + if (con_driver->con == csw) { retval = -EBUSY; + goto err; + } } - if (retval) - goto err; - desc = csw->con_startup(); if (!desc) { retval = -ENODEV; -- cgit v1.1 From 6550be9f62bfc4dacbdbd8cb7afe0df661da77bf Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Mon, 2 May 2016 17:19:46 +0800 Subject: serial: 8250_dw: fix wrong logic in dw8250_check_lcr() Commit cdcea058e510 ("serial: 8250_dw: Avoid serial_outx code duplicate with new dw8250_check_lcr()") introduce a wrong logic when write val to LCR reg. When CONFIG_64BIT enabled, __raw_writeq is used unconditionally. The __raw_readq/__raw_writeq is introduced by commit bca2092d7897 ("serial: 8250_dw: Use 64-bit access for OCTEON.") for OCTEON. So for 64BIT && !PORT_OCTEON, we better to use coincident write function. Fixes: cdcea058e510("serial: 8250_dw: Avoid serial_outx code duplicate with new dw8250_check_lcr()") Signed-off-by: Kefeng Wang Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5364de3..e199696 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -104,15 +104,16 @@ static void dw8250_check_lcr(struct uart_port *p, int value) dw8250_force_idle(p); #ifdef CONFIG_64BIT - __raw_writeq(value & 0xff, offset); -#else + if (p->type == PORT_OCTEON) + __raw_writeq(value & 0xff, offset); + else +#endif if (p->iotype == UPIO_MEM32) writel(value, offset); else if (p->iotype == UPIO_MEM32BE) iowrite32be(value, offset); else writeb(value, offset); -#endif } /* * FIXME: this deadlocks if port->lock is already held -- cgit v1.1 From 7da4b8b7378790dd1e4af1bb7522863127fa1438 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 3 May 2016 14:01:51 -0700 Subject: serial: core: Fix port mutex assert if lockdep disabled commit 4047b37122d1 ("serial: core: Prevent unsafe uart port access, part 1") added lockdep assertion for port mutex but fails to check if debug_locks has disabled lockdep (so lock state is no longer reliable). Use lockdep_assert_held() instead, which properly checks lockdep state as well. Reported-by: Tony Lindgren Signed-off-by: Peter Hurley Tested-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index d529b5c..a333c59 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -95,9 +95,7 @@ static inline void uart_port_deref(struct uart_port *uport) static inline struct uart_port *uart_port_check(struct uart_state *state) { -#ifdef CONFIG_LOCKDEP - WARN_ON(!lockdep_is_held(&state->port.mutex)); -#endif + lockdep_assert_held(&state->port.mutex); return state->uart_port; } -- cgit v1.1 From d20bb59af64667a16f2468b54fc0adb2f824a3b6 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 7 Mar 2016 08:31:14 +0200 Subject: MAINTAINERS: 8250: remove website reference This website is obsolete, as it has not been updated in more than a decade. Cc: "Theodore Ts'o" Signed-off-by: Baruch Siach Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a727d99..0e6b547 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -175,7 +175,6 @@ F: drivers/net/ethernet/realtek/r8169.c 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER M: Greg Kroah-Hartman L: linux-serial@vger.kernel.org -W: http://serial.sourceforge.net S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git F: drivers/tty/serial/8250* -- cgit v1.1