Commit e5233658 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-3.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg KH:
 "Here are a few fixes for 3.13-rc5 that resolve a number of reported
  tty and serial driver issues"

* tag 'tty-3.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: xuartps: Properly guard sysrq specific code
  n_tty: Fix apparent order of echoed output
  serial: 8250_dw: add new ACPI IDs
  serial: 8250_dw: Fix LCR workaround regression
  tty: Fix hang at ldsem_down_read()
parents 1aba038b c2db11ec
...@@ -93,6 +93,7 @@ struct n_tty_data { ...@@ -93,6 +93,7 @@ struct n_tty_data {
size_t canon_head; size_t canon_head;
size_t echo_head; size_t echo_head;
size_t echo_commit; size_t echo_commit;
size_t echo_mark;
DECLARE_BITMAP(char_map, 256); DECLARE_BITMAP(char_map, 256);
/* private to n_tty_receive_overrun (single-threaded) */ /* private to n_tty_receive_overrun (single-threaded) */
...@@ -336,6 +337,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata) ...@@ -336,6 +337,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
{ {
ldata->read_head = ldata->canon_head = ldata->read_tail = 0; ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
ldata->echo_mark = 0;
ldata->line_start = 0; ldata->line_start = 0;
ldata->erasing = 0; ldata->erasing = 0;
...@@ -787,6 +789,7 @@ static void commit_echoes(struct tty_struct *tty) ...@@ -787,6 +789,7 @@ static void commit_echoes(struct tty_struct *tty)
size_t head; size_t head;
head = ldata->echo_head; head = ldata->echo_head;
ldata->echo_mark = head;
old = ldata->echo_commit - ldata->echo_tail; old = ldata->echo_commit - ldata->echo_tail;
/* Process committed echoes if the accumulated # of bytes /* Process committed echoes if the accumulated # of bytes
...@@ -811,10 +814,11 @@ static void process_echoes(struct tty_struct *tty) ...@@ -811,10 +814,11 @@ static void process_echoes(struct tty_struct *tty)
size_t echoed; size_t echoed;
if ((!L_ECHO(tty) && !L_ECHONL(tty)) || if ((!L_ECHO(tty) && !L_ECHONL(tty)) ||
ldata->echo_commit == ldata->echo_tail) ldata->echo_mark == ldata->echo_tail)
return; return;
mutex_lock(&ldata->output_lock); mutex_lock(&ldata->output_lock);
ldata->echo_commit = ldata->echo_mark;
echoed = __process_echoes(tty); echoed = __process_echoes(tty);
mutex_unlock(&ldata->output_lock); mutex_unlock(&ldata->output_lock);
...@@ -822,6 +826,7 @@ static void process_echoes(struct tty_struct *tty) ...@@ -822,6 +826,7 @@ static void process_echoes(struct tty_struct *tty)
tty->ops->flush_chars(tty); tty->ops->flush_chars(tty);
} }
/* NB: echo_mark and echo_head should be equivalent here */
static void flush_echoes(struct tty_struct *tty) static void flush_echoes(struct tty_struct *tty)
{ {
struct n_tty_data *ldata = tty->disc_data; struct n_tty_data *ldata = tty->disc_data;
......
...@@ -96,7 +96,8 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value) ...@@ -96,7 +96,8 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
if (offset == UART_LCR) { if (offset == UART_LCR) {
int tries = 1000; int tries = 1000;
while (tries--) { while (tries--) {
if (value == p->serial_in(p, UART_LCR)) unsigned int lcr = p->serial_in(p, UART_LCR);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
return; return;
dw8250_force_idle(p); dw8250_force_idle(p);
writeb(value, p->membase + (UART_LCR << p->regshift)); writeb(value, p->membase + (UART_LCR << p->regshift));
...@@ -132,7 +133,8 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) ...@@ -132,7 +133,8 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
if (offset == UART_LCR) { if (offset == UART_LCR) {
int tries = 1000; int tries = 1000;
while (tries--) { while (tries--) {
if (value == p->serial_in(p, UART_LCR)) unsigned int lcr = p->serial_in(p, UART_LCR);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
return; return;
dw8250_force_idle(p); dw8250_force_idle(p);
writel(value, p->membase + (UART_LCR << p->regshift)); writel(value, p->membase + (UART_LCR << p->regshift));
...@@ -455,6 +457,8 @@ MODULE_DEVICE_TABLE(of, dw8250_of_match); ...@@ -455,6 +457,8 @@ MODULE_DEVICE_TABLE(of, dw8250_of_match);
static const struct acpi_device_id dw8250_acpi_match[] = { static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C4", 0 }, { "INT33C4", 0 },
{ "INT33C5", 0 }, { "INT33C5", 0 },
{ "INT3434", 0 },
{ "INT3435", 0 },
{ "80860F0A", 0 }, { "80860F0A", 0 },
{ }, { },
}; };
......
...@@ -240,6 +240,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) ...@@ -240,6 +240,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
continue; continue;
} }
#ifdef SUPPORT_SYSRQ
/* /*
* uart_handle_sysrq_char() doesn't work if * uart_handle_sysrq_char() doesn't work if
* spinlocked, for some reason * spinlocked, for some reason
...@@ -253,6 +254,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) ...@@ -253,6 +254,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
} }
spin_lock(&port->lock); spin_lock(&port->lock);
} }
#endif
port->icount.rx++; port->icount.rx++;
......
...@@ -86,11 +86,21 @@ static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem) ...@@ -86,11 +86,21 @@ static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem)
return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
} }
/*
* ldsem_cmpxchg() updates @*old with the last-known sem->count value.
* Returns 1 if count was successfully changed; @*old will have @new value.
* Returns 0 if count was not changed; @*old will have most recent sem->count
*/
static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem) static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem)
{ {
long tmp = *old; long tmp = atomic_long_cmpxchg(&sem->count, *old, new);
*old = atomic_long_cmpxchg(&sem->count, *old, new); if (tmp == *old) {
return *old == tmp; *old = new;
return 1;
} else {
*old = tmp;
return 0;
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment