From d4260b51699082c7dea257bea002d79394e876e0 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Thu, 16 Oct 2014 14:19:47 -0400 Subject: serial: Fix upstat_t sparse warnings Commit 299245a145b2ad4cfb4c5432eb1264299f55e7e0, serial: core: Privatize modem status enable flags, introduced the upstat_t type and matching bit definitions. The purpose is to produce sparse warnings if the wrong bit definitions are used (by warning of implicit integer conversions). Fix implicit conversion to integer return type from uart_cts_enabled() and uart_dcd_enabled(). Fixes the following sparse warnings: drivers/tty/serial/serial_core.c:63:30: warning: incorrect type in return expression (different base types) drivers/tty/serial/serial_core.c:63:30: expected int drivers/tty/serial/serial_core.c:63:30: got restricted upstat_t include/linux/serial_core.h:364:30: warning: incorrect type in return expression (different base types) include/linux/serial_core.h:364:30: expected bool include/linux/serial_core.h:364:30: got restricted upstat_t include/linux/serial_core.h:364:30: warning: incorrect type in return expression (different base types) include/linux/serial_core.h:364:30: expected bool include/linux/serial_core.h:364:30: got restricted upstat_t Reported-by: Fengguang Wu Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 21c2e05c1bc3..bccf4bac22f5 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -367,7 +367,7 @@ static inline int uart_tx_stopped(struct uart_port *port) static inline bool uart_cts_enabled(struct uart_port *uport) { - return uport->status & UPSTAT_CTS_ENABLE; + return !!(uport->status & UPSTAT_CTS_ENABLE); } /* -- cgit v1.2.3-59-g8ed1b From 8f166e00196fcb16364c9c39dab6fe7b72e63f18 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Thu, 16 Oct 2014 14:59:41 -0400 Subject: tty: Remove tty_pair_get_tty()/tty_pair_get_pty() api tty_pair_get_pty() has no in-tree users and tty_pair_get_tty() has only one file-local user. Remove the external declarations, the export declarations, and declare tty_pair_get_tty() static. Signed-off-by: Peter Hurley Reviewed-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 16 +++++----------- include/linux/tty.h | 3 --- 2 files changed, 5 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index c322e7af7373..d3e71331641b 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2703,23 +2703,17 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) return 0; } -struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) +/* + * if pty, return the slave side (real_tty) + * otherwise, return self + */ +static struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) { if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) tty = tty->link; return tty; } -EXPORT_SYMBOL(tty_pair_get_tty); - -struct tty_struct *tty_pair_get_pty(struct tty_struct *tty) -{ - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - return tty; - return tty->link; -} -EXPORT_SYMBOL(tty_pair_get_pty); /* * Split this up, as gcc can choke on it otherwise.. diff --git a/include/linux/tty.h b/include/linux/tty.h index 5171ef8f7b85..b36b0b445c1f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -498,9 +498,6 @@ extern int tty_init_termios(struct tty_struct *tty); extern int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty); -extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); -extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); - extern struct mutex tty_mutex; extern spinlock_t tty_files_lock; -- cgit v1.2.3-59-g8ed1b From e1c2296c3485158304bfad5a80e89078463d70c8 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Thu, 16 Oct 2014 14:59:48 -0400 Subject: tty: Move session_of_pgrp() and make static tiocspgrp() is the lone caller of session_of_pgrp(); relocate and limit to file scope. Signed-off-by: Peter Hurley Reviewed-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 21 +++++++++++++++++++++ include/linux/kernel.h | 3 --- kernel/exit.c | 21 --------------------- 3 files changed, 21 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 114854c5554b..ae8f53c7972d 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2515,6 +2515,27 @@ struct pid *tty_get_pgrp(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(tty_get_pgrp); +/* + * This checks not only the pgrp, but falls back on the pid if no + * satisfactory pgrp is found. I dunno - gdb doesn't work correctly + * without this... + * + * The caller must hold rcu lock or the tasklist lock. + */ +static struct pid *session_of_pgrp(struct pid *pgrp) +{ + struct task_struct *p; + struct pid *sid = NULL; + + p = pid_task(pgrp, PIDTYPE_PGID); + if (p == NULL) + p = pid_task(pgrp, PIDTYPE_PID); + if (p != NULL) + sid = task_session(p); + + return sid; +} + /** * tiocgpgrp - get process group * @tty: tty passed by user diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3d770f5564b8..01bc530fbfcb 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -411,9 +411,6 @@ extern int __kernel_text_address(unsigned long addr); extern int kernel_text_address(unsigned long addr); extern int func_ptr_is_kernel_text(void *ptr); -struct pid; -extern struct pid *session_of_pgrp(struct pid *pgrp); - unsigned long int_sqrt(unsigned long); extern void bust_spinlocks(int yes); diff --git a/kernel/exit.c b/kernel/exit.c index 5d30019ff953..6a3e2e5004ba 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -214,27 +214,6 @@ repeat: goto repeat; } -/* - * This checks not only the pgrp, but falls back on the pid if no - * satisfactory pgrp is found. I dunno - gdb doesn't work correctly - * without this... - * - * The caller must hold rcu lock or the tasklist lock. - */ -struct pid *session_of_pgrp(struct pid *pgrp) -{ - struct task_struct *p; - struct pid *sid = NULL; - - p = pid_task(pgrp, PIDTYPE_PGID); - if (p == NULL) - p = pid_task(pgrp, PIDTYPE_PID); - if (p != NULL) - sid = task_session(p); - - return sid; -} - /* * Determine if a process group is "orphaned", according to the POSIX * definition in 2.2.2.52. Orphaned process groups are not to be affected -- cgit v1.2.3-59-g8ed1b From 3ff51a199f9e85aed843471bc10dae9e94dbb0fc Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:12:46 -0500 Subject: tty: Remove TTY_HUPPING Now that tty_ldisc_hangup() does not drop the tty lock, it is no longer possible to observe TTY_HUPPING while holding the tty lock on another cpu. Remove TTY_HUPPING bit definition. Reviewed-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 12 +----------- drivers/tty/tty_ldisc.c | 3 +-- include/linux/tty.h | 1 - 3 files changed, 2 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 9d1e247ee330..873793c426df 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -690,9 +690,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) return; } - /* some functions below drop BTM, so we need this bit */ - set_bit(TTY_HUPPING, &tty->flags); - /* inuse_filps is protected by the single tty lock, this really needs to change if we want to flush the workqueue with the lock held */ @@ -717,10 +714,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) while (refs--) tty_kref_put(tty); - /* - * it drops BTM and thus races with reopen - * we protect the race by TTY_HUPPING - */ tty_ldisc_hangup(tty); spin_lock_irq(&tty->ctrl_lock); @@ -752,8 +745,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) * can't yet guarantee all that. */ set_bit(TTY_HUPPED, &tty->flags); - clear_bit(TTY_HUPPING, &tty->flags); - tty_unlock(tty); if (f) @@ -1461,8 +1452,7 @@ static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; - if (test_bit(TTY_CLOSING, &tty->flags) || - test_bit(TTY_HUPPING, &tty->flags)) + if (test_bit(TTY_CLOSING, &tty->flags)) return -EIO; if (driver->type == TTY_DRIVER_TYPE_PTY && diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 28858ebe2912..49001fa2ea2f 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -544,8 +544,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) old_ldisc = tty->ldisc; - if (test_bit(TTY_HUPPING, &tty->flags) || - test_bit(TTY_HUPPED, &tty->flags)) { + if (test_bit(TTY_HUPPED, &tty->flags)) { /* We were raced by the hangup method. It will have stomped the ldisc data and closed the ldisc down */ tty_ldisc_enable_pair(tty, o_tty); diff --git a/include/linux/tty.h b/include/linux/tty.h index b36b0b445c1f..ff0dd7aeaf3b 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -321,7 +321,6 @@ struct tty_file_private { #define TTY_PTY_LOCK 16 /* pty private */ #define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ #define TTY_HUPPED 18 /* Post driver->hangup() */ -#define TTY_HUPPING 21 /* ->hangup() in progress */ #define TTY_LDISC_HALTED 22 /* Line discipline is halted */ #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) -- cgit v1.2.3-59-g8ed1b From 04980706c8febe41ec598116b174bd3a2dc82355 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:12:52 -0500 Subject: tty: Remove TTY_CLOSING Now that re-open is not permitted for a legacy BSD pty master, using TTY_CLOSING to indicate when a tty can be torn-down is no longer necessary. Reviewed-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 14 ++------------ include/linux/tty.h | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 66d6bcc24c7e..ea8c6cae8d12 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1197,7 +1197,7 @@ void tty_write_message(struct tty_struct *tty, char *msg) if (tty) { mutex_lock(&tty->atomic_write_lock); tty_lock(tty); - if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { + if (tty->ops->write && tty->count > 0) { tty_unlock(tty); tty->ops->write(tty, msg, strlen(msg)); } else @@ -1879,16 +1879,6 @@ int tty_release(struct inode *inode, struct file *filp) /* * Perform some housekeeping before deciding whether to return. * - * Set the TTY_CLOSING flag if this was the last open. In the - * case of a pty we may have to wait around for the other side - * to close, and TTY_CLOSING makes sure we can't be reopened. - */ - if (tty_closing) - set_bit(TTY_CLOSING, &tty->flags); - if (o_tty_closing) - set_bit(TTY_CLOSING, &o_tty->flags); - - /* * If _either_ side is closing, make sure there aren't any * processes that still think tty or o_tty is their controlling * tty. @@ -1903,7 +1893,7 @@ int tty_release(struct inode *inode, struct file *filp) mutex_unlock(&tty_mutex); tty_unlock_pair(tty, o_tty); - /* At this point the TTY_CLOSING flag should ensure a dead tty + /* At this point, the tty->count == 0 should ensure a dead tty cannot be re-opened by a racing opener */ /* check whether both sides are closing ... */ diff --git a/include/linux/tty.h b/include/linux/tty.h index ff0dd7aeaf3b..35b29f0750f8 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -316,7 +316,6 @@ struct tty_file_private { #define TTY_EXCLUSIVE 3 /* Exclusive open mode */ #define TTY_DEBUG 4 /* Debugging */ #define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ -#define TTY_CLOSING 7 /* ->close() in progress */ #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 */ -- cgit v1.2.3-59-g8ed1b From 62462aefeb5aff092fc97037d9c12a4afe95a3ff Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:12:58 -0500 Subject: tty: Simplify tty_ldisc_release() interface Passing the 'other' tty to tty_ldisc_release() only makes sense for a pty pair; make o_tty function local instead. Reviewed-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 2 +- drivers/tty/tty_ldisc.c | 15 +++++++-------- include/linux/tty.h | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index f5b62b99489d..cd9550820a58 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1892,7 +1892,7 @@ int tty_release(struct inode *inode, struct file *filp) /* * Ask the line discipline code to release its structures */ - tty_ldisc_release(tty, o_tty); + tty_ldisc_release(tty); /* Wait for pending work before tty destruction commmences */ tty_flush_works(tty); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 49001fa2ea2f..1c4d7b6d8a76 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -756,18 +756,17 @@ static void tty_ldisc_kill(struct tty_struct *tty) /** * tty_ldisc_release - release line discipline - * @tty: tty being shut down - * @o_tty: pair tty for pty/tty pairs - * - * Called during the final close of a tty/pty pair in order to shut down - * the line discpline layer. On exit the ldisc assigned is N_TTY and the - * ldisc has not been opened. + * @tty: tty being shut down (or one end of pty pair) * - * Holding ldisc_sem write lock serializes tty->ldisc changes. + * Called during the final close of a tty or a pty pair in order to shut + * down the line discpline layer. On exit, each ldisc assigned is N_TTY and + * each ldisc has not been opened. */ -void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) +void tty_ldisc_release(struct tty_struct *tty) { + struct tty_struct *o_tty = tty->link; + /* * Shutdown this line discipline. As this is the final close, * it does not race with the set_ldisc code path. diff --git a/include/linux/tty.h b/include/linux/tty.h index 35b29f0750f8..af1a7f3e4e4a 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -557,7 +557,7 @@ extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); extern int tty_set_ldisc(struct tty_struct *tty, int ldisc); extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty); -extern void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty); +extern void tty_ldisc_release(struct tty_struct *tty); extern void tty_ldisc_init(struct tty_struct *tty); extern void tty_ldisc_deinit(struct tty_struct *tty); extern void tty_ldisc_begin(void); -- cgit v1.2.3-59-g8ed1b From 2aff5e2bc62db43e05c814461a08aff0fc2b7fe5 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:13:01 -0500 Subject: tty: Change tty lock order to master->slave When releasing the master pty, the slave pty also needs to be locked to prevent concurrent tty count changes for the slave pty and to ensure that only one parallel master and slave release observe the final close, and proceed to destruct the pty pair. Conversely, when releasing the slave pty, locking the master pty is not necessary (since the master's state can be inferred by the slave tty count). Introduce tty_lock_slave()/tty_unlock_slave() which acquires/releases the tty lock of the slave pty. Remove tty_lock_pair()/tty_unlock_pair(). Dropping the tty_lock is no longer required to re-establish a stable lock order. Reviewed-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 10 ++++++---- drivers/tty/tty_mutex.c | 32 +++++++++++++------------------- include/linux/tty.h | 7 ++----- 3 files changed, 21 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index bd7cde3c56ef..4ecee2856ece 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1790,7 +1790,9 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - tty_unlock(tty); + /* If tty is pty master, lock the slave pty (stable lock order) */ + tty_lock_slave(o_tty); + /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1804,8 +1806,6 @@ int tty_release(struct inode *inode, struct file *filp) * Thus this test wouldn't be triggered at the time the slave closed, * so we do it now. */ - tty_lock_pair(tty, o_tty); - while (1) { do_sleep = 0; @@ -1879,7 +1879,9 @@ int tty_release(struct inode *inode, struct file *filp) /* check whether both sides are closing ... */ final = !tty->count && !(o_tty && o_tty->count); - tty_unlock_pair(tty, o_tty); + tty_unlock_slave(o_tty); + tty_unlock(tty); + /* At this point, the tty->count == 0 should ensure a dead tty cannot be re-opened by a racing opener */ diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 2e41abebbcba..f43e995c7a0f 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,6 +4,11 @@ #include #include +/* + * Nested tty locks are necessary for releasing pty pairs. + * The stable lock order is master pty first, then slave pty. + */ + /* Legacy tty mutex glue */ enum { @@ -45,29 +50,18 @@ void __lockfunc tty_unlock(struct tty_struct *tty) } EXPORT_SYMBOL(tty_unlock); -/* - * Getting the big tty mutex for a pair of ttys with lock ordering - * On a non pty/tty pair tty2 can be NULL which is just fine. - */ -void __lockfunc tty_lock_pair(struct tty_struct *tty, - struct tty_struct *tty2) +void __lockfunc tty_lock_slave(struct tty_struct *tty) { - if (tty < tty2) { - tty_lock(tty); - tty_lock_nested(tty2, TTY_MUTEX_NESTED); - } else { - if (tty2 && tty2 != tty) - tty_lock(tty2); + if (tty && tty != tty->link) { + WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) || + !tty->driver->type == TTY_DRIVER_TYPE_PTY || + !tty->driver->type == PTY_TYPE_SLAVE); tty_lock_nested(tty, TTY_MUTEX_NESTED); } } -EXPORT_SYMBOL(tty_lock_pair); -void __lockfunc tty_unlock_pair(struct tty_struct *tty, - struct tty_struct *tty2) +void __lockfunc tty_unlock_slave(struct tty_struct *tty) { - tty_unlock(tty); - if (tty2 && tty2 != tty) - tty_unlock(tty2); + if (tty && tty != tty->link) + tty_unlock(tty); } -EXPORT_SYMBOL(tty_unlock_pair); diff --git a/include/linux/tty.h b/include/linux/tty.h index af1a7f3e4e4a..a07b4b415db8 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -638,11 +638,8 @@ extern long vt_compat_ioctl(struct tty_struct *tty, /* functions for preparation of BKL removal */ extern void __lockfunc tty_lock(struct tty_struct *tty); extern void __lockfunc tty_unlock(struct tty_struct *tty); -extern void __lockfunc tty_lock_pair(struct tty_struct *tty, - struct tty_struct *tty2); -extern void __lockfunc tty_unlock_pair(struct tty_struct *tty, - struct tty_struct *tty2); - +extern void __lockfunc tty_lock_slave(struct tty_struct *tty); +extern void __lockfunc tty_unlock_slave(struct tty_struct *tty); /* * this shall be called only from where BTM is held (like close) * -- cgit v1.2.3-59-g8ed1b From 2febdb632bb96235b94b8fccaf882a78f8f4b2bb Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:13:02 -0500 Subject: tty: Preset lock subclass for nested tty locks Eliminate the requirement of specifying the tty lock nesting at lock time; instead, set the lock subclass for slave ptys at pty install (normal ttys and master ptys use subclass 0). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 2 ++ drivers/tty/tty_mutex.c | 19 +++++++++---------- include/linux/tty.h | 1 + 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index bdb8fd1a2026..11db7dc8676b 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -399,6 +399,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, if (!o_tty) goto err_put_module; + tty_set_lock_subclass(o_tty); + if (legacy) { /* We always use new tty termios data so we can do this the easy way .. */ diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index f43e995c7a0f..4486741190c4 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -13,15 +13,14 @@ enum { TTY_MUTEX_NORMAL, - TTY_MUTEX_NESTED, + TTY_MUTEX_SLAVE, }; /* * Getting the big tty mutex. */ -static void __lockfunc tty_lock_nested(struct tty_struct *tty, - unsigned int subclass) +void __lockfunc tty_lock(struct tty_struct *tty) { if (tty->magic != TTY_MAGIC) { pr_err("L Bad %p\n", tty); @@ -29,12 +28,7 @@ static void __lockfunc tty_lock_nested(struct tty_struct *tty, return; } tty_kref_get(tty); - mutex_lock_nested(&tty->legacy_mutex, subclass); -} - -void __lockfunc tty_lock(struct tty_struct *tty) -{ - return tty_lock_nested(tty, TTY_MUTEX_NORMAL); + mutex_lock(&tty->legacy_mutex); } EXPORT_SYMBOL(tty_lock); @@ -56,7 +50,7 @@ void __lockfunc tty_lock_slave(struct tty_struct *tty) WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) || !tty->driver->type == TTY_DRIVER_TYPE_PTY || !tty->driver->type == PTY_TYPE_SLAVE); - tty_lock_nested(tty, TTY_MUTEX_NESTED); + tty_lock(tty); } } @@ -65,3 +59,8 @@ void __lockfunc tty_unlock_slave(struct tty_struct *tty) if (tty && tty != tty->link) tty_unlock(tty); } + +void tty_set_lock_subclass(struct tty_struct *tty) +{ + lockdep_set_subclass(&tty->legacy_mutex, TTY_MUTEX_SLAVE); +} diff --git a/include/linux/tty.h b/include/linux/tty.h index a07b4b415db8..196c352a5ce8 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -640,6 +640,7 @@ extern void __lockfunc tty_lock(struct tty_struct *tty); extern void __lockfunc tty_unlock(struct tty_struct *tty); extern void __lockfunc tty_lock_slave(struct tty_struct *tty); extern void __lockfunc tty_unlock_slave(struct tty_struct *tty); +extern void tty_set_lock_subclass(struct tty_struct *tty); /* * this shall be called only from where BTM is held (like close) * -- cgit v1.2.3-59-g8ed1b From 35af935ee47eb4548e0052733e9d75328e260fa1 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:13:03 -0500 Subject: tty: Remove tty_unhangup() declaration The tty_unhangup() function is not defined. Reviewed-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/tty.h b/include/linux/tty.h index 196c352a5ce8..e33ea1a0c2d0 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -435,7 +435,6 @@ extern int is_ignored(int sig); extern int tty_signal(int sig, struct tty_struct *tty); extern void tty_hangup(struct tty_struct *tty); extern void tty_vhangup(struct tty_struct *tty); -extern void tty_unhangup(struct file *filp); extern int tty_hung_up_p(struct file *filp); extern void do_SAK(struct tty_struct *tty); extern void __do_SAK(struct tty_struct *tty); -- cgit v1.2.3-59-g8ed1b From 86c80a8e2ab443e9c4261b3499de4ce808399104 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:13:09 -0500 Subject: tty: Flush ldisc buffer atomically with tty flip buffers tty_ldisc_flush() first clears the line discipline input buffer, then clears the tty flip buffers. However, this allows for existing data in the tty flip buffers to be added after the ldisc input buffer has been cleared, but before the flip buffers have been cleared. Add an optional ldisc parameter to tty_buffer_flush() to allow tty_ldisc_flush() to pass the ldisc to clear. NB: Initially, the plan was to do this automatically in tty_buffer_flush(). However, an audit of the behavior of existing line disciplines showed that performing a ldisc buffer flush on ioctl(TCFLSH) was not always the outcome. For example, some line disciplines have flush_buffer() methods but not ioctl() methods, so a ->flush_buffer() command would be unexpected. Reviewed-by: Alan Cox Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 10 ++++++++-- drivers/tty/tty_io.c | 2 +- drivers/tty/tty_ldisc.c | 12 +++++------- include/linux/tty.h | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 143deb62467d..3605103fc1ac 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -202,14 +202,16 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) /** * tty_buffer_flush - flush full tty buffers * @tty: tty to flush + * @ld: optional ldisc ptr (must be referenced) * - * flush all the buffers containing receive data. + * flush all the buffers containing receive data. If ld != NULL, + * flush the ldisc input buffer. * * Locking: takes buffer lock to ensure single-threaded flip buffer * 'consumer' */ -void tty_buffer_flush(struct tty_struct *tty) +void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) { struct tty_port *port = tty->port; struct tty_bufhead *buf = &port->buf; @@ -223,6 +225,10 @@ void tty_buffer_flush(struct tty_struct *tty) buf->head = next; } buf->head->read = buf->head->commit; + + if (ld && ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); + atomic_dec(&buf->priority); mutex_unlock(&buf->lock); } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 4ecee2856ece..aa83cd1bf071 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2890,7 +2890,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TCIFLUSH: case TCIOFLUSH: /* flush tty buffer and allow ldisc to process ioctl */ - tty_buffer_flush(tty); + tty_buffer_flush(tty, NULL); break; } break; diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 6368dd95e137..b66a81d0549e 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -397,19 +397,17 @@ static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty, * tty_ldisc_flush - flush line discipline queue * @tty: tty * - * Flush the line discipline queue (if any) for this tty. If there - * is no line discipline active this is a no-op. + * Flush the line discipline queue (if any) and the tty flip buffers + * for this tty. */ void tty_ldisc_flush(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); + + tty_buffer_flush(tty, ld); + if (ld) tty_ldisc_deref(ld); - } - tty_buffer_flush(tty); } EXPORT_SYMBOL_GPL(tty_ldisc_flush); diff --git a/include/linux/tty.h b/include/linux/tty.h index e33ea1a0c2d0..f6835ea1079a 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -441,7 +441,7 @@ extern void __do_SAK(struct tty_struct *tty); extern void no_tty(void); extern void tty_flush_to_ldisc(struct tty_struct *tty); extern void tty_buffer_free_all(struct tty_port *port); -extern void tty_buffer_flush(struct tty_struct *tty); +extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); extern void tty_buffer_init(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); -- cgit v1.2.3-59-g8ed1b From 904326ecac022ebaeb39cdfb206fd3b6551cdfca Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Thu, 16 Oct 2014 16:54:21 -0400 Subject: tty,serial: Unify UPF_* and ASYNC_* flag definitions The userspace-defined ASYNC_* flags in include/uapi/linux/tty_flags.h are the authoritative bit definitions for the serial_struct flags, and thus for any derivative values or fields. Although the serial core provides the TIOCSSERIAL and TIOCGSERIAL ioctls to set and retrieve these flags from userspace, it defines these bits independently, as UPF_* macros. Define the UPF_* macros which are userspace-modifiable directly from the ASYNC_* symbolic constants. Add compile-time test to ensure the bits changeable by TIOCSSERIAL match the defined range in the uapi header. Add ASYNCB_MAGIC_MULTIPLIER to the uapi header since this bit is programmable by userspace. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 47 ++++++++++++++++++++++++++++-------------- include/uapi/linux/tty_flags.h | 6 +++++- 2 files changed, 37 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index bccf4bac22f5..ad9329669aba 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -160,21 +160,33 @@ struct uart_port { /* flags must be updated while holding port mutex */ upf_t flags; -#define UPF_FOURPORT ((__force upf_t) (1 << 1)) -#define UPF_SAK ((__force upf_t) (1 << 2)) -#define UPF_SPD_MASK ((__force upf_t) (0x1030)) -#define UPF_SPD_HI ((__force upf_t) (0x0010)) -#define UPF_SPD_VHI ((__force upf_t) (0x0020)) -#define UPF_SPD_CUST ((__force upf_t) (0x0030)) -#define UPF_SPD_SHI ((__force upf_t) (0x1000)) -#define UPF_SPD_WARP ((__force upf_t) (0x1010)) -#define UPF_SKIP_TEST ((__force upf_t) (1 << 6)) -#define UPF_AUTO_IRQ ((__force upf_t) (1 << 7)) -#define UPF_HARDPPS_CD ((__force upf_t) (1 << 11)) -#define UPF_LOW_LATENCY ((__force upf_t) (1 << 13)) -#define UPF_BUGGY_UART ((__force upf_t) (1 << 14)) + /* + * These flags must be equivalent to the flags defined in + * include/uapi/linux/tty_flags.h which are the userspace definitions + * assigned from the serial_struct flags in uart_set_info() + * [for bit definitions in the UPF_CHANGE_MASK] + * + * Bits [0..UPF_LAST_USER] are userspace defined/visible/changeable + * except bit 15 (UPF_NO_TXEN_TEST) which is masked off. + * The remaining bits are serial-core specific and not modifiable by + * userspace. + */ +#define UPF_FOURPORT ((__force upf_t) ASYNC_FOURPORT /* 1 */ ) +#define UPF_SAK ((__force upf_t) ASYNC_SAK /* 2 */ ) +#define UPF_SPD_HI ((__force upf_t) ASYNC_SPD_HI /* 4 */ ) +#define UPF_SPD_VHI ((__force upf_t) ASYNC_SPD_VHI /* 5 */ ) +#define UPF_SPD_CUST ((__force upf_t) ASYNC_SPD_CUST /* 0x0030 */ ) +#define UPF_SPD_WARP ((__force upf_t) ASYNC_SPD_WARP /* 0x1010 */ ) +#define UPF_SPD_MASK ((__force upf_t) ASYNC_SPD_MASK /* 0x1030 */ ) +#define UPF_SKIP_TEST ((__force upf_t) ASYNC_SKIP_TEST /* 6 */ ) +#define UPF_AUTO_IRQ ((__force upf_t) ASYNC_AUTO_IRQ /* 7 */ ) +#define UPF_HARDPPS_CD ((__force upf_t) ASYNC_HARDPPS_CD /* 11 */ ) +#define UPF_SPD_SHI ((__force upf_t) ASYNC_SPD_SHI /* 12 */ ) +#define UPF_LOW_LATENCY ((__force upf_t) ASYNC_LOW_LATENCY /* 13 */ ) +#define UPF_BUGGY_UART ((__force upf_t) ASYNC_BUGGY_UART /* 14 */ ) #define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15)) -#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16)) +#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ ) + /* Port has hardware-assisted h/w flow control (iow, auto-RTS *not* auto-CTS) */ #define UPF_HARD_FLOW ((__force upf_t) (1 << 21)) /* Port has hardware-assisted s/w flow control */ @@ -190,9 +202,14 @@ struct uart_port { #define UPF_DEAD ((__force upf_t) (1 << 30)) #define UPF_IOREMAP ((__force upf_t) (1 << 31)) -#define UPF_CHANGE_MASK ((__force upf_t) (0x17fff)) +#define __UPF_CHANGE_MASK 0x17fff +#define UPF_CHANGE_MASK ((__force upf_t) __UPF_CHANGE_MASK) #define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY)) +#if __UPF_CHANGE_MASK > ASYNC_FLAGS +#error Change mask not equivalent to userspace-visible bit defines +#endif + /* status must be updated while holding port lock */ upstat_t status; diff --git a/include/uapi/linux/tty_flags.h b/include/uapi/linux/tty_flags.h index eefcb483a2c0..7b516f7ee7e6 100644 --- a/include/uapi/linux/tty_flags.h +++ b/include/uapi/linux/tty_flags.h @@ -6,6 +6,8 @@ * shared by the tty_port flags structures. * * Define ASYNCB_* for convenient use with {test,set,clear}_bit. + * + * Bits [0..ASYNCB_LAST_USER] are userspace defined/visible/changeable */ #define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes * on the callout port */ @@ -26,7 +28,8 @@ #define ASYNCB_BUGGY_UART 14 /* This is a buggy UART, skip some safety * checks. Note: can be dangerous! */ #define ASYNCB_AUTOPROBE 15 /* Port was autoprobed by PCI or PNP code */ -#define ASYNCB_LAST_USER 15 +#define ASYNCB_MAGIC_MULTIPLIER 16 /* Use special CLK or divisor */ +#define ASYNCB_LAST_USER 16 /* Internal flags used only by kernel */ #define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ @@ -57,6 +60,7 @@ #define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY) #define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART) #define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE) +#define ASYNC_MAGIC_MULTIPLIER (1U << ASYNCB_MAGIC_MULTIPLIER) #define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1) #define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \ -- cgit v1.2.3-59-g8ed1b From 1d597e7c266658697843352c5c030e20f48c6230 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:26:26 -0500 Subject: tty: Remove defunct pcxe_open() declaration pcxe_open() has no definition in mainline; remove declaration. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tty.h b/include/linux/tty.h index f6835ea1079a..97cfb3108e29 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -621,10 +621,6 @@ extern long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file, extern void serial_console_init(void); -/* pcxx.c */ - -extern int pcxe_open(struct tty_struct *tty, struct file *filp); - /* vt.c */ extern int vt_ioctl(struct tty_struct *tty, -- cgit v1.2.3-59-g8ed1b From b9104f5cec3b7d8fb4068bce5ddc8240dc7b81f7 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:26:27 -0500 Subject: tty: Remove defunct serial_console_init() declaration serial_console_init() is not defined by the tty core; remove declaration. Note that the powerpc arch boot code contains a serial_console_init() declaration in arch/powerpc/boot/ops.h which is restricted to the powerpc arch boot. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tty.h b/include/linux/tty.h index 97cfb3108e29..c52a689e09aa 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -617,10 +617,6 @@ extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, extern long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -/* serial.c */ - -extern void serial_console_init(void); - /* vt.c */ extern int vt_ioctl(struct tty_struct *tty, -- cgit v1.2.3-59-g8ed1b From e979f3b712c8b8ae44bab591427f1647dd25aa0d Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Tue, 21 Oct 2014 15:23:03 -0700 Subject: tty: serial: bcm63xx: Eliminate unnecessary request/release functions We don't really need to perform the ioremap "on demand" so it's simpler just to do it from the probe function. This also lets us eliminate the UART_REG_SIZE constant and rely on the resource information passed in from the DT or platform code. Signed-off-by: Kevin Cernekee Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/bcm63xx_uart.c | 30 ++++++++++-------------------- include/linux/serial_bcm63xx.h | 2 -- 2 files changed, 10 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 109dea711318..e04e5805ae6e 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -588,20 +588,7 @@ static void bcm_uart_set_termios(struct uart_port *port, */ static int bcm_uart_request_port(struct uart_port *port) { - unsigned int size; - - size = UART_REG_SIZE; - if (!request_mem_region(port->mapbase, size, "bcm63xx")) { - dev_err(port->dev, "Memory region busy\n"); - return -EBUSY; - } - - port->membase = ioremap(port->mapbase, size); - if (!port->membase) { - dev_err(port->dev, "Unable to map registers\n"); - release_mem_region(port->mapbase, size); - return -EBUSY; - } + /* UARTs always present */ return 0; } @@ -610,8 +597,7 @@ static int bcm_uart_request_port(struct uart_port *port) */ static void bcm_uart_release_port(struct uart_port *port) { - release_mem_region(port->mapbase, UART_REG_SIZE); - iounmap(port->membase); + /* Nothing to release ... */ } /* @@ -833,13 +819,20 @@ static int bcm_uart_probe(struct platform_device *pdev) if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) return -EINVAL; - if (ports[pdev->id].membase) + port = &ports[pdev->id]; + if (port->membase) return -EBUSY; + memset(port, 0, sizeof(*port)); res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_mem) return -ENODEV; + port->mapbase = res_mem->start; + port->membase = devm_ioremap_resource(&pdev->dev, res_mem); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res_irq) return -ENODEV; @@ -849,10 +842,7 @@ static int bcm_uart_probe(struct platform_device *pdev) if (IS_ERR(clk)) return -ENODEV; - port = &ports[pdev->id]; - memset(port, 0, sizeof(*port)); port->iotype = UPIO_MEM; - port->mapbase = res_mem->start; port->irq = res_irq->start; port->ops = &bcm_uart_ops; port->flags = UPF_BOOT_AUTOCONF; diff --git a/include/linux/serial_bcm63xx.h b/include/linux/serial_bcm63xx.h index a80aa1a5bee2..570e964dc899 100644 --- a/include/linux/serial_bcm63xx.h +++ b/include/linux/serial_bcm63xx.h @@ -116,6 +116,4 @@ UART_FIFO_PARERR_MASK | \ UART_FIFO_BRKDET_MASK) -#define UART_REG_SIZE 24 - #endif /* _LINUX_SERIAL_BCM63XX_H */ -- cgit v1.2.3-59-g8ed1b From 413ba6385382bc80e4bf2f58efa900e82e810b11 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 12:40:04 -0500 Subject: tty: Convert tty->closing to int tty->closing is a bitfield member; prevent corruption from non-atomic update by assigning a unique memory location. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/tty.h b/include/linux/tty.h index c52a689e09aa..7d66ae508e5c 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -284,7 +284,7 @@ struct tty_struct { #define N_TTY_BUF_SIZE 4096 - unsigned char closing:1; + int closing; unsigned char *write_buf; int write_cnt; /* If the tty has a pending do_SAK, queue it here - akpm */ -- cgit v1.2.3-59-g8ed1b From 732a84a037a4de29b54e0b4e6cb6f9b3813e29e5 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 5 Nov 2014 13:11:43 -0500 Subject: serial: core: Pass termios to set_ldisc() notifications UART drivers which enable modem status interrupts when switching to N_PPS line discipline need to determine if modem status interrupts should be disabled when switching from N_PPS. Specifically, the set_ldisc() notification needs to evaluate UART_ENABLE_MS() which requires termios->c_cflag. Convert in-tree UART drivers to new interface. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 4 ++-- drivers/tty/serial/amba-pl010.c | 4 ++-- drivers/tty/serial/atmel_serial.c | 4 ++-- drivers/tty/serial/bfin_uart.c | 5 +++-- drivers/tty/serial/clps711x.c | 5 +++-- drivers/tty/serial/serial_core.c | 2 +- include/linux/serial_core.h | 2 +- 7 files changed, 14 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 223503299e99..116b5a75f1af 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2609,9 +2609,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, } static void -serial8250_set_ldisc(struct uart_port *port, int new) +serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios) { - if (new == N_PPS) { + if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; serial8250_enable_ms(port); } else diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 00ae8dcabc9b..230bc7a290d5 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -479,9 +479,9 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&uap->port.lock, flags); } -static void pl010_set_ldisc(struct uart_port *port, int new) +static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios) { - if (new == N_PPS) { + if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; pl010_enable_ms(port); } else diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index b9987109b2da..6a1d960e2e82 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2056,9 +2056,9 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&port->lock, flags); } -static void atmel_set_ldisc(struct uart_port *port, int new) +static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios) { - if (new == N_PPS) { + if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; atmel_enable_ms(port); } else { diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 7da9911e95f0..44b27ec32341 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -944,12 +944,13 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser) * Enable the IrDA function if tty->ldisc.num is N_IRDA. * In other cases, disable IrDA function. */ -static void bfin_serial_set_ldisc(struct uart_port *port, int ld) +static void bfin_serial_set_ldisc(struct uart_port *port, + struct ktermios *termios) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; unsigned int val; - switch (ld) { + switch (termios->c_line) { case N_IRDA: val = UART_GET_GCTL(uart); val |= (UMOD_IRDA | RPOLC); diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index acfe31773643..f963c4c48085 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -225,13 +225,14 @@ static void uart_clps711x_break_ctl(struct uart_port *port, int break_state) writel(ubrlcr, port->membase + UBRLCR_OFFSET); } -static void uart_clps711x_set_ldisc(struct uart_port *port, int ld) +static void uart_clps711x_set_ldisc(struct uart_port *port, + struct ktermios *termios) { if (!port->line) { struct clps711x_port *s = dev_get_drvdata(port->dev); regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON1_SIREN, - (ld == N_IRDA) ? SYSCON1_SIREN : 0); + (termios->c_line == N_IRDA) ? SYSCON1_SIREN : 0); } } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 5209eaaa7225..c5fb08cfbdb1 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1247,7 +1247,7 @@ static void uart_set_ldisc(struct tty_struct *tty) if (uport->ops->set_ldisc) { mutex_lock(&state->port.mutex); - uport->ops->set_ldisc(uport, tty->termios.c_line); + uport->ops->set_ldisc(uport, &tty->termios); mutex_unlock(&state->port.mutex); } } diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index ad9329669aba..40b4cc4f8e1d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -63,7 +63,7 @@ struct uart_ops { void (*flush_buffer)(struct uart_port *); void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); - void (*set_ldisc)(struct uart_port *, int new); + void (*set_ldisc)(struct uart_port *, struct ktermios *); void (*pm)(struct uart_port *, unsigned int state, unsigned int oldstate); -- cgit v1.2.3-59-g8ed1b From a5f276f10ff70da89b349df445e944c8cd87956c Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Thu, 6 Nov 2014 22:46:13 +0100 Subject: serial_core: Handle TIOC[GS]RS485 ioctls. The following drivers: 8250_core, atmel_serial, max310x, mcf, omap-serial and sci16is7xx implement code to handle RS485 ioctls. In order to avoid code duplication, we implement a simple ioctl handler on the serial_core layer. This handler can be used by all the other drivers instead of duplicating code. Until this is the only RS485 ioctl handler, it will try first the rs485_config callback and if it is not present it will call the driver specific ioctl. Reviewed-by: Alan Cox Cc: Greg Kroah-Hartman Cc: Jiri Slaby Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 45 ++++++++++++++++++++++++++++++++++++++++ include/linux/serial_core.h | 3 +++ 2 files changed, 48 insertions(+) (limited to 'include/linux') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index c5fb08cfbdb1..ab4db1dcc474 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1152,6 +1152,39 @@ static int uart_get_icount(struct tty_struct *tty, return 0; } +static int uart_get_rs485_config(struct uart_port *port, + struct serial_rs485 __user *rs485) +{ + if (!port->rs485_config) + return -ENOIOCTLCMD; + + if (copy_to_user(rs485, &port->rs485, sizeof(port->rs485))) + return -EFAULT; + return 0; +} + +static int uart_set_rs485_config(struct uart_port *port, + struct serial_rs485 __user *rs485_user) +{ + struct serial_rs485 rs485; + int ret; + + if (!port->rs485_config) + return -ENOIOCTLCMD; + + if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) + return -EFAULT; + + ret = port->rs485_config(port, &rs485); + if (ret) + return ret; + + if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485))) + return -EFAULT; + + return 0; +} + /* * Called via sys_ioctl. We can use spin_lock_irq() here. */ @@ -1223,6 +1256,18 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, * protected against the tty being hung up. */ switch (cmd) { + case TIOCGRS485: + ret = uart_get_rs485_config(state->uart_port, uarg); + break; + + case TIOCSRS485: + ret = uart_set_rs485_config(state->uart_port, uarg); + break; + } + if (ret != -ENOIOCTLCMD) + goto out; + + switch (cmd) { case TIOCSERGETLSR: /* Get line status register */ ret = uart_get_lsr_info(tty, state, uarg); break; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 40b4cc4f8e1d..3231a43f6acf 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -131,6 +131,8 @@ struct uart_port { void (*pm)(struct uart_port *, unsigned int state, unsigned int old); void (*handle_break)(struct uart_port *); + int (*rs485_config)(struct uart_port *, + struct serial_rs485 *rs485); unsigned int irq; /* irq number */ unsigned long irqflags; /* irq flags */ unsigned int uartclk; /* base uart clock */ @@ -231,6 +233,7 @@ struct uart_port { unsigned char unused[2]; struct attribute_group *attr_group; /* port specific attributes */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ + struct serial_rs485 rs485; void *private_data; /* generic platform data pointer */ }; -- cgit v1.2.3-59-g8ed1b From 039ec1f010e6b058f497381d5a6bb840e160b4ac Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Thu, 6 Nov 2014 09:22:53 +0100 Subject: serial/8250: Remove obsolete handling of rs485 ioctls There is no more users for this functions. All the 8250 drivers are using the rs485 handler on serial_core instead. Reviewed-by: Alan Cox Cc: Jiri Slaby Cc: Sebastian Andrzej Siewior Cc: Alan Cox Cc: Tony Lindgren Cc: Peter Hurley Cc: Yoshihiro YUNOMAE Cc: Andy Shevchenko Cc: Ingo Molnar Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 39 ------------------------------------- include/linux/serial_8250.h | 3 --- 2 files changed, 42 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 3f2c6576ab4e..30522d680014 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -3005,42 +3005,6 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) return 0; } -static int serial8250_ioctl(struct uart_port *port, unsigned int cmd, - unsigned long arg) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - int ret; - struct serial_rs485 rs485_config; - - if (!up->rs485_config) - return -ENOIOCTLCMD; - - switch (cmd) { - case TIOCSRS485: - if (copy_from_user(&rs485_config, (void __user *)arg, - sizeof(rs485_config))) - return -EFAULT; - - ret = up->rs485_config(up, &rs485_config); - if (ret) - return ret; - - memcpy(&up->rs485, &rs485_config, sizeof(rs485_config)); - - return 0; - case TIOCGRS485: - if (copy_to_user((void __user *)arg, &up->rs485, - sizeof(up->rs485))) - return -EFAULT; - return 0; - default: - break; - } - - return -ENOIOCTLCMD; -} - static const char * serial8250_type(struct uart_port *port) { @@ -3072,7 +3036,6 @@ static struct uart_ops serial8250_pops = { .request_port = serial8250_request_port, .config_port = serial8250_config_port, .verify_port = serial8250_verify_port, - .ioctl = serial8250_ioctl, #ifdef CONFIG_CONSOLE_POLL .poll_get_char = serial8250_get_poll_char, .poll_put_char = serial8250_put_poll_char, @@ -3615,8 +3578,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.fifosize = up->port.fifosize; uart->tx_loadsz = up->tx_loadsz; uart->capabilities = up->capabilities; - uart->rs485_config = up->rs485_config; - uart->rs485 = up->rs485; uart->port.throttle = up->port.throttle; uart->port.unthrottle = up->port.unthrottle; uart->port.rs485_config = up->port.rs485_config; diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 3df10d5f154b..e02acf0a0ec9 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -97,13 +97,10 @@ struct uart_8250_port { unsigned char msr_saved_flags; struct uart_8250_dma *dma; - struct serial_rs485 rs485; /* 8250 specific callbacks */ int (*dl_read)(struct uart_8250_port *); void (*dl_write)(struct uart_8250_port *, int); - int (*rs485_config)(struct uart_8250_port *, - struct serial_rs485 *rs485); }; static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up) -- cgit v1.2.3-59-g8ed1b From 3ffb1a8193bead7bf4ef0fec2dae050c70e4c1c1 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Wed, 12 Nov 2014 12:53:59 -0800 Subject: serial: core: Add big-endian iotype Since most drivers interpret UPIO_MEM32 to mean "little-endian" and use readl/writel to access the registers, add a parallel UPIO_MEM32BE to request the use of big-endian MMIO accessors (ioread32be/iowrite32be). Signed-off-by: Kevin Cernekee Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ include/linux/serial_core.h | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 5c8b8f50f787..57ca61b14670 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2153,6 +2153,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) break; case UPIO_MEM: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: snprintf(address, sizeof(address), @@ -2796,6 +2797,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) (port1->hub6 == port2->hub6); case UPIO_MEM: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: return (port1->mapbase == port2->mapbase); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 3231a43f6acf..057038cf2788 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -142,12 +142,13 @@ struct uart_port { unsigned char iotype; /* io access style */ unsigned char unused1; -#define UPIO_PORT (0) -#define UPIO_HUB6 (1) -#define UPIO_MEM (2) -#define UPIO_MEM32 (3) -#define UPIO_AU (4) /* Au1x00 and RT288x type IO */ -#define UPIO_TSI (5) /* Tsi108/109 type IO */ +#define UPIO_PORT (0) /* 8b I/O port access */ +#define UPIO_HUB6 (1) /* Hub6 ISA card */ +#define UPIO_MEM (2) /* 8b MMIO access */ +#define UPIO_MEM32 (3) /* 32b little endian */ +#define UPIO_MEM32BE (4) /* 32b big endian */ +#define UPIO_AU (5) /* Au1x00 and RT288x type IO */ +#define UPIO_TSI (6) /* Tsi108/109 type IO */ unsigned int read_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */ -- cgit v1.2.3-59-g8ed1b