mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 21:30:54 +07:00
Merge branch 'serial'
* serial: imx: Check for NULL pointer deref before calling tty_encode_baud_rate atmel_serial: fix hang in set_termios when crtscts is enabled MAINTAINERS: update 8250 section, give Alan Cox a name tty: fix sanity check pty: Narrow the race on ldisc locking tty: fix unused warning when TCGETX is not defined ldisc: debug aids ldisc: Make sure the ldisc isn't active when we close it tty: Fix leaks introduced by the shift to separate ldisc objects Fix conflicts in drivers/char/pty.c due to earlier version of the ldisc race narrowing.
This commit is contained in:
commit
15bdb56526
@ -157,9 +157,10 @@ S: Maintained
|
|||||||
F: drivers/net/r8169.c
|
F: drivers/net/r8169.c
|
||||||
|
|
||||||
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
|
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
|
||||||
|
P: Alan Cox
|
||||||
|
M: alan@lxorguk.ukuu.org.uk
|
||||||
L: linux-serial@vger.kernel.org
|
L: linux-serial@vger.kernel.org
|
||||||
W: http://serial.sourceforge.net
|
W: http://serial.sourceforge.net
|
||||||
M: alan@lxorguk.ukuu.org.uk
|
|
||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
F: drivers/serial/8250*
|
F: drivers/serial/8250*
|
||||||
F: include/linux/serial_8250.h
|
F: include/linux/serial_8250.h
|
||||||
|
@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty)
|
|||||||
* a count.
|
* a count.
|
||||||
*
|
*
|
||||||
* FIXME: Our pty_write method is called with our ldisc lock held but
|
* FIXME: Our pty_write method is called with our ldisc lock held but
|
||||||
* not our partners. We can't just take the other one blindly without
|
* not our partners. We can't just wait on the other one blindly without
|
||||||
* risking deadlocks.
|
* risking deadlocks. At some point when everything has settled down we need
|
||||||
|
* to look into making pty_write at least able to sleep over an ldisc change.
|
||||||
|
*
|
||||||
|
* The return on no ldisc is a bit counter intuitive but the logic works
|
||||||
|
* like this. During an ldisc change the other end will flush its buffers. We
|
||||||
|
* thus return the full length which is identical to the case where we had
|
||||||
|
* proper locking and happened to queue the bytes just before the flush during
|
||||||
|
* the ldisc change.
|
||||||
*/
|
*/
|
||||||
static int pty_write(struct tty_struct *tty, const unsigned char *buf,
|
static int pty_write(struct tty_struct *tty, const unsigned char *buf,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
struct tty_struct *to = tty->link;
|
struct tty_struct *to = tty->link;
|
||||||
int c;
|
struct tty_ldisc *ld;
|
||||||
|
int c = count;
|
||||||
|
|
||||||
if (!to || !to->ldisc || tty->stopped)
|
if (!to || tty->stopped)
|
||||||
return 0;
|
return 0;
|
||||||
|
ld = tty_ldisc_ref(to);
|
||||||
|
|
||||||
c = to->receive_room;
|
if (ld) {
|
||||||
if (c > count)
|
c = to->receive_room;
|
||||||
c = count;
|
if (c > count)
|
||||||
to->ldisc->ops->receive_buf(to, buf, NULL, c);
|
c = count;
|
||||||
|
ld->ops->receive_buf(to, buf, NULL, c);
|
||||||
|
tty_ldisc_deref(ld);
|
||||||
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty)
|
|||||||
static int pty_chars_in_buffer(struct tty_struct *tty)
|
static int pty_chars_in_buffer(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct tty_struct *to = tty->link;
|
struct tty_struct *to = tty->link;
|
||||||
int count;
|
struct tty_ldisc *ld;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
/* We should get the line discipline lock for "tty->link" */
|
/* We should get the line discipline lock for "tty->link" */
|
||||||
if (!to || !to->ldisc || !to->ldisc->ops->chars_in_buffer)
|
if (!to)
|
||||||
|
return 0;
|
||||||
|
/* We cannot take a sleeping reference here without deadlocking with
|
||||||
|
an ldisc change - but it doesn't really matter */
|
||||||
|
ld = tty_ldisc_ref(to);
|
||||||
|
if (ld == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* The ldisc must report 0 if no characters available to be read */
|
/* The ldisc must report 0 if no characters available to be read */
|
||||||
count = to->ldisc->ops->chars_in_buffer(to);
|
if (ld->ops->chars_in_buffer)
|
||||||
|
count = ld->ops->chars_in_buffer(to);
|
||||||
|
|
||||||
|
tty_ldisc_deref(ld);
|
||||||
|
|
||||||
if (tty->driver->subtype == PTY_TYPE_SLAVE)
|
if (tty->driver->subtype == PTY_TYPE_SLAVE)
|
||||||
return count;
|
return count;
|
||||||
@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty)
|
|||||||
{
|
{
|
||||||
struct tty_struct *to = tty->link;
|
struct tty_struct *to = tty->link;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct tty_ldisc *ld;
|
||||||
|
|
||||||
if (!to || !to->ldisc)
|
if (!to)
|
||||||
|
return;
|
||||||
|
ld = tty_ldisc_ref(to);
|
||||||
|
|
||||||
|
/* The other end is changing discipline */
|
||||||
|
if (!ld)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (to->ldisc->ops->flush_buffer)
|
if (ld->ops->flush_buffer)
|
||||||
to->ldisc->ops->flush_buffer(to);
|
to->ldisc->ops->flush_buffer(to);
|
||||||
|
tty_ldisc_deref(ld);
|
||||||
|
|
||||||
if (to->packet) {
|
if (to->packet) {
|
||||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||||
|
@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty)
|
|||||||
tty->count++;
|
tty->count++;
|
||||||
tty->driver = driver; /* N.B. why do this every time?? */
|
tty->driver = driver; /* N.B. why do this every time?? */
|
||||||
|
|
||||||
|
mutex_lock(&tty->ldisc_mutex);
|
||||||
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
|
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
|
||||||
|
mutex_unlock(&tty->ldisc_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
void __user *p = (void __user *)arg;
|
void __user *p = (void __user *)arg;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct ktermios kterm;
|
struct ktermios kterm;
|
||||||
struct termiox ktermx;
|
|
||||||
|
|
||||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||||
@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCGETX
|
#ifdef TCGETX
|
||||||
case TCGETX:
|
case TCGETX: {
|
||||||
|
struct termiox ktermx;
|
||||||
if (real_tty->termiox == NULL)
|
if (real_tty->termiox == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
mutex_lock(&real_tty->termios_mutex);
|
mutex_lock(&real_tty->termios_mutex);
|
||||||
@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
|
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
case TCSETX:
|
case TCSETX:
|
||||||
return set_termiox(real_tty, p, 0);
|
return set_termiox(real_tty, p, 0);
|
||||||
case TCSETXW:
|
case TCSETXW:
|
||||||
|
@ -207,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld)
|
|||||||
ldo->refcount--;
|
ldo->refcount--;
|
||||||
module_put(ldo->owner);
|
module_put(ldo->owner);
|
||||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||||
|
WARN_ON(ld->refcount);
|
||||||
kfree(ld);
|
kfree(ld);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -793,6 +794,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|||||||
/* Avoid racing set_ldisc */
|
/* Avoid racing set_ldisc */
|
||||||
mutex_lock(&tty->ldisc_mutex);
|
mutex_lock(&tty->ldisc_mutex);
|
||||||
/* Switch back to N_TTY */
|
/* Switch back to N_TTY */
|
||||||
|
tty_ldisc_halt(tty);
|
||||||
|
tty_ldisc_wait_idle(tty);
|
||||||
tty_ldisc_reinit(tty);
|
tty_ldisc_reinit(tty);
|
||||||
/* At this point we have a closed ldisc and we want to
|
/* At this point we have a closed ldisc and we want to
|
||||||
reopen it. We could defer this to the next open but
|
reopen it. We could defer this to the next open but
|
||||||
|
@ -1104,11 +1104,13 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||||||
/* update the per-port timeout */
|
/* update the per-port timeout */
|
||||||
uart_update_timeout(port, termios->c_cflag, baud);
|
uart_update_timeout(port, termios->c_cflag, baud);
|
||||||
|
|
||||||
/* save/disable interrupts and drain transmitter */
|
/*
|
||||||
|
* save/disable interrupts. The tty layer will ensure that the
|
||||||
|
* transmitter is empty if requested by the caller, so there's
|
||||||
|
* no need to wait for it here.
|
||||||
|
*/
|
||||||
imr = UART_GET_IMR(port);
|
imr = UART_GET_IMR(port);
|
||||||
UART_PUT_IDR(port, -1);
|
UART_PUT_IDR(port, -1);
|
||||||
while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
|
|
||||||
cpu_relax();
|
|
||||||
|
|
||||||
/* disable receiver and transmitter */
|
/* disable receiver and transmitter */
|
||||||
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
|
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
|
||||||
|
@ -924,11 +924,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||||||
rational_best_approximation(16 * div * baud, sport->port.uartclk,
|
rational_best_approximation(16 * div * baud, sport->port.uartclk,
|
||||||
1 << 16, 1 << 16, &num, &denom);
|
1 << 16, 1 << 16, &num, &denom);
|
||||||
|
|
||||||
tdiv64 = sport->port.uartclk;
|
if (port->info && port->info->port.tty) {
|
||||||
tdiv64 *= num;
|
tdiv64 = sport->port.uartclk;
|
||||||
do_div(tdiv64, denom * 16 * div);
|
tdiv64 *= num;
|
||||||
tty_encode_baud_rate(sport->port.info->port.tty,
|
do_div(tdiv64, denom * 16 * div);
|
||||||
(speed_t)tdiv64, (speed_t)tdiv64);
|
tty_encode_baud_rate(sport->port.info->port.tty,
|
||||||
|
(speed_t)tdiv64, (speed_t)tdiv64);
|
||||||
|
}
|
||||||
|
|
||||||
num -= 1;
|
num -= 1;
|
||||||
denom -= 1;
|
denom -= 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user