mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
TTY/Serial driver fixes for 4.3-rc5
Here are a few bug fixes for the tty core that resolve reported issues, and some serial driver fixes as well (including the much-reported imx driver problem.) All of these have been in linux-next with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlYZOMsACgkQMUfUDdst+ykHVQCdEiZhPNcK5Y6E80pzvhGSSkHa s+kAoJLT4hqzehZkP1hVImxKmWQpq1d1 =8zsH -----END PGP SIGNATURE----- Merge tag 'tty-4.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver fixes from Greg KH: "Here are a few bug fixes for the tty core that resolve reported issues, and some serial driver fixes as well (including the much-reported imx driver problem) All of these have been in linux-next with no reported problems" * tag 'tty-4.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: drivers/tty: require read access for controlling terminal serial: 8250: add uart_config entry for PORT_RT2880 tty: fix data race on tty_buffer.commit tty: fix data race in tty_buffer_flush tty: fix data race in flush_to_ldisc tty: fix stall caused by missing memory barrier in drivers/tty/n_tty.c serial: atmel: fix error path of probe function tty: don't leak cdev in tty_cdev_add() Revert "serial: imx: remove unbalanced clk_prepare"
This commit is contained in:
commit
97d0c931c0
6 changed files with 79 additions and 28 deletions
|
@ -343,8 +343,7 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
|
|||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
if (waitqueue_active(&tty->link->read_wait))
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1382,8 +1381,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
|
|||
put_tty_queue(c, ldata);
|
||||
smp_store_release(&ldata->canon_head, ldata->read_head);
|
||||
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
|
||||
if (waitqueue_active(&tty->read_wait))
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1667,8 +1665,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
|||
|
||||
if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
|
||||
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
|
||||
if (waitqueue_active(&tty->read_wait))
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1887,10 +1884,8 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
|
|||
}
|
||||
|
||||
/* The termios change make the tty ready for I/O */
|
||||
if (waitqueue_active(&tty->write_wait))
|
||||
wake_up_interruptible(&tty->write_wait);
|
||||
if (waitqueue_active(&tty->read_wait))
|
||||
wake_up_interruptible(&tty->read_wait);
|
||||
wake_up_interruptible(&tty->write_wait);
|
||||
wake_up_interruptible(&tty->read_wait);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -261,6 +261,14 @@ configured less than Maximum supported fifo bytes */
|
|||
UART_FCR7_64BYTE,
|
||||
.flags = UART_CAP_FIFO,
|
||||
},
|
||||
[PORT_RT2880] = {
|
||||
.name = "Palmchip BK-3103",
|
||||
.fifo_size = 16,
|
||||
.tx_loadsz = 16,
|
||||
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||||
.rxtrig_bytes = {1, 4, 8, 14},
|
||||
.flags = UART_CAP_FIFO,
|
||||
},
|
||||
};
|
||||
|
||||
/* Uart divisor latch read */
|
||||
|
|
|
@ -2786,7 +2786,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
|||
ret = atmel_init_gpios(port, &pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to initialize GPIOs.");
|
||||
goto err;
|
||||
goto err_clear_bit;
|
||||
}
|
||||
|
||||
ret = atmel_init_port(port, pdev);
|
||||
|
|
|
@ -1631,12 +1631,12 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
|
|||
int locked = 1;
|
||||
int retval;
|
||||
|
||||
retval = clk_prepare_enable(sport->clk_per);
|
||||
retval = clk_enable(sport->clk_per);
|
||||
if (retval)
|
||||
return;
|
||||
retval = clk_prepare_enable(sport->clk_ipg);
|
||||
retval = clk_enable(sport->clk_ipg);
|
||||
if (retval) {
|
||||
clk_disable_unprepare(sport->clk_per);
|
||||
clk_disable(sport->clk_per);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1675,8 +1675,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
|
|||
if (locked)
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
clk_disable_unprepare(sport->clk_per);
|
||||
clk_disable(sport->clk_ipg);
|
||||
clk_disable(sport->clk_per);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1777,7 +1777,15 @@ imx_console_setup(struct console *co, char *options)
|
|||
|
||||
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
|
||||
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
clk_disable(sport->clk_ipg);
|
||||
if (retval) {
|
||||
clk_unprepare(sport->clk_ipg);
|
||||
goto error_console;
|
||||
}
|
||||
|
||||
retval = clk_prepare(sport->clk_per);
|
||||
if (retval)
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
|
||||
error_console:
|
||||
return retval;
|
||||
|
|
|
@ -242,7 +242,10 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
|
|||
atomic_inc(&buf->priority);
|
||||
|
||||
mutex_lock(&buf->lock);
|
||||
while ((next = buf->head->next) != NULL) {
|
||||
/* paired w/ release in __tty_buffer_request_room; ensures there are
|
||||
* no pending memory accesses to the freed buffer
|
||||
*/
|
||||
while ((next = smp_load_acquire(&buf->head->next)) != NULL) {
|
||||
tty_buffer_free(port, buf->head);
|
||||
buf->head = next;
|
||||
}
|
||||
|
@ -290,7 +293,10 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
|
|||
if (n != NULL) {
|
||||
n->flags = flags;
|
||||
buf->tail = n;
|
||||
b->commit = b->used;
|
||||
/* paired w/ acquire in flush_to_ldisc(); ensures
|
||||
* flush_to_ldisc() sees buffer data.
|
||||
*/
|
||||
smp_store_release(&b->commit, b->used);
|
||||
/* paired w/ acquire in flush_to_ldisc(); ensures the
|
||||
* latest commit value can be read before the head is
|
||||
* advanced to the next buffer
|
||||
|
@ -393,7 +399,10 @@ void tty_schedule_flip(struct tty_port *port)
|
|||
{
|
||||
struct tty_bufhead *buf = &port->buf;
|
||||
|
||||
buf->tail->commit = buf->tail->used;
|
||||
/* paired w/ acquire in flush_to_ldisc(); ensures
|
||||
* flush_to_ldisc() sees buffer data.
|
||||
*/
|
||||
smp_store_release(&buf->tail->commit, buf->tail->used);
|
||||
schedule_work(&buf->work);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_schedule_flip);
|
||||
|
@ -467,7 +476,7 @@ static void flush_to_ldisc(struct work_struct *work)
|
|||
struct tty_struct *tty;
|
||||
struct tty_ldisc *disc;
|
||||
|
||||
tty = port->itty;
|
||||
tty = READ_ONCE(port->itty);
|
||||
if (tty == NULL)
|
||||
return;
|
||||
|
||||
|
@ -491,7 +500,10 @@ static void flush_to_ldisc(struct work_struct *work)
|
|||
* is advancing to the next buffer
|
||||
*/
|
||||
next = smp_load_acquire(&head->next);
|
||||
count = head->commit - head->read;
|
||||
/* paired w/ release in __tty_buffer_request_room() or in
|
||||
* tty_buffer_flush(); ensures we see the committed buffer data
|
||||
*/
|
||||
count = smp_load_acquire(&head->commit) - head->read;
|
||||
if (!count) {
|
||||
if (next == NULL) {
|
||||
check_other_closed(tty);
|
||||
|
|
|
@ -2128,8 +2128,24 @@ static int tty_open(struct inode *inode, struct file *filp)
|
|||
if (!noctty &&
|
||||
current->signal->leader &&
|
||||
!current->signal->tty &&
|
||||
tty->session == NULL)
|
||||
__proc_set_tty(tty);
|
||||
tty->session == NULL) {
|
||||
/*
|
||||
* Don't let a process that only has write access to the tty
|
||||
* obtain the privileges associated with having a tty as
|
||||
* controlling terminal (being able to reopen it with full
|
||||
* access through /dev/tty, being able to perform pushback).
|
||||
* Many distributions set the group of all ttys to "tty" and
|
||||
* grant write-only access to all terminals for setgid tty
|
||||
* binaries, which should not imply full privileges on all ttys.
|
||||
*
|
||||
* This could theoretically break old code that performs open()
|
||||
* on a write-only file descriptor. In that case, it might be
|
||||
* necessary to also permit this if
|
||||
* inode_permission(inode, MAY_READ) == 0.
|
||||
*/
|
||||
if (filp->f_mode & FMODE_READ)
|
||||
__proc_set_tty(tty);
|
||||
}
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
read_unlock(&tasklist_lock);
|
||||
tty_unlock(tty);
|
||||
|
@ -2418,7 +2434,7 @@ static int fionbio(struct file *file, int __user *p)
|
|||
* Takes ->siglock() when updating signal->tty
|
||||
*/
|
||||
|
||||
static int tiocsctty(struct tty_struct *tty, int arg)
|
||||
static int tiocsctty(struct tty_struct *tty, struct file *file, int arg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -2452,6 +2468,13 @@ static int tiocsctty(struct tty_struct *tty, int arg)
|
|||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
/* See the comment in tty_open(). */
|
||||
if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) {
|
||||
ret = -EPERM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
proc_set_tty(tty);
|
||||
unlock:
|
||||
read_unlock(&tasklist_lock);
|
||||
|
@ -2844,7 +2867,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
no_tty();
|
||||
return 0;
|
||||
case TIOCSCTTY:
|
||||
return tiocsctty(tty, arg);
|
||||
return tiocsctty(tty, file, arg);
|
||||
case TIOCGPGRP:
|
||||
return tiocgpgrp(tty, real_tty, p);
|
||||
case TIOCSPGRP:
|
||||
|
@ -3151,13 +3174,18 @@ struct class *tty_class;
|
|||
static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
|
||||
unsigned int index, unsigned int count)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* init here, since reused cdevs cause crashes */
|
||||
driver->cdevs[index] = cdev_alloc();
|
||||
if (!driver->cdevs[index])
|
||||
return -ENOMEM;
|
||||
cdev_init(driver->cdevs[index], &tty_fops);
|
||||
driver->cdevs[index]->ops = &tty_fops;
|
||||
driver->cdevs[index]->owner = driver->owner;
|
||||
return cdev_add(driver->cdevs[index], dev, count);
|
||||
err = cdev_add(driver->cdevs[index], dev, count);
|
||||
if (err)
|
||||
kobject_put(&driver->cdevs[index]->kobj);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue