Commit a8d706986c5ee65354d8ddd88fe2dadfd2184991

Authored by Linus Torvalds

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

Pull tty/serial fixes from Greg KH:
 "Here are a few tty/serial fixes for 3.15-rc3 that resolve a number of
  reported issues in the 8250 and samsung serial drivers, as well as a
  character loss fix for the tty core that was caused by the lock
  removal patches a release ago"

* tag 'tty-3.15-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial_core: fix uart PORT_UNKNOWN handling
  serial: samsung: Change barrier() to cpu_relax() in console output
  serial: samsung: don't check config for every character
  serial: samsung: Use the passed in "port", fixing kgdb w/ no console
  serial: 8250: Fix thread unsafe __dma_tx_complete function
  8250_core: Fix unwanted TX chars write
  tty: Fix race condition between __tty_buffer_request_room and flush_to_ldisc

Showing 6 changed files Side-by-side Diff

drivers/tty/serial/8250/8250_core.c
... ... @@ -1520,7 +1520,7 @@
1520 1520 status = serial8250_rx_chars(up, status);
1521 1521 }
1522 1522 serial8250_modem_status(up);
1523   - if (status & UART_LSR_THRE)
  1523 + if (!up->dma && (status & UART_LSR_THRE))
1524 1524 serial8250_tx_chars(up);
1525 1525  
1526 1526 spin_unlock_irqrestore(&port->lock, flags);
drivers/tty/serial/8250/8250_dma.c
... ... @@ -20,12 +20,15 @@
20 20 struct uart_8250_port *p = param;
21 21 struct uart_8250_dma *dma = p->dma;
22 22 struct circ_buf *xmit = &p->port.state->xmit;
  23 + unsigned long flags;
23 24  
24   - dma->tx_running = 0;
25   -
26 25 dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
27 26 UART_XMIT_SIZE, DMA_TO_DEVICE);
28 27  
  28 + spin_lock_irqsave(&p->port.lock, flags);
  29 +
  30 + dma->tx_running = 0;
  31 +
29 32 xmit->tail += dma->tx_size;
30 33 xmit->tail &= UART_XMIT_SIZE - 1;
31 34 p->port.icount.tx += dma->tx_size;
... ... @@ -35,6 +38,8 @@
35 38  
36 39 if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port))
37 40 serial8250_tx_dma(p);
  41 +
  42 + spin_unlock_irqrestore(&p->port.lock, flags);
38 43 }
39 44  
40 45 static void __dma_rx_complete(void *param)
drivers/tty/serial/samsung.c
... ... @@ -1446,8 +1446,8 @@
1446 1446 static void s3c24xx_serial_put_poll_char(struct uart_port *port,
1447 1447 unsigned char c)
1448 1448 {
1449   - unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
1450   - unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
  1449 + unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
  1450 + unsigned int ucon = rd_regl(port, S3C2410_UCON);
1451 1451  
1452 1452 /* not possible to xmit on unconfigured port */
1453 1453 if (!s3c24xx_port_configured(ucon))
... ... @@ -1455,7 +1455,7 @@
1455 1455  
1456 1456 while (!s3c24xx_serial_console_txrdy(port, ufcon))
1457 1457 cpu_relax();
1458   - wr_regb(cons_uart, S3C2410_UTXH, c);
  1458 + wr_regb(port, S3C2410_UTXH, c);
1459 1459 }
1460 1460  
1461 1461 #endif /* CONFIG_CONSOLE_POLL */
1462 1462  
1463 1463  
1464 1464  
... ... @@ -1463,22 +1463,23 @@
1463 1463 static void
1464 1464 s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
1465 1465 {
1466   - unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
1467   - unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
  1466 + unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
1468 1467  
1469   - /* not possible to xmit on unconfigured port */
1470   - if (!s3c24xx_port_configured(ucon))
1471   - return;
1472   -
1473 1468 while (!s3c24xx_serial_console_txrdy(port, ufcon))
1474   - barrier();
1475   - wr_regb(cons_uart, S3C2410_UTXH, ch);
  1469 + cpu_relax();
  1470 + wr_regb(port, S3C2410_UTXH, ch);
1476 1471 }
1477 1472  
1478 1473 static void
1479 1474 s3c24xx_serial_console_write(struct console *co, const char *s,
1480 1475 unsigned int count)
1481 1476 {
  1477 + unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
  1478 +
  1479 + /* not possible to xmit on unconfigured port */
  1480 + if (!s3c24xx_port_configured(ucon))
  1481 + return;
  1482 +
1482 1483 uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
1483 1484 }
1484 1485  
drivers/tty/serial/serial_core.c
... ... @@ -137,6 +137,11 @@
137 137 return 1;
138 138  
139 139 /*
  140 + * Make sure the device is in D0 state.
  141 + */
  142 + uart_change_pm(state, UART_PM_STATE_ON);
  143 +
  144 + /*
140 145 * Initialise and allocate the transmit and temporary
141 146 * buffer.
142 147 */
143 148  
144 149  
... ... @@ -825,25 +830,29 @@
825 830 * If we fail to request resources for the
826 831 * new port, try to restore the old settings.
827 832 */
828   - if (retval && old_type != PORT_UNKNOWN) {
  833 + if (retval) {
829 834 uport->iobase = old_iobase;
830 835 uport->type = old_type;
831 836 uport->hub6 = old_hub6;
832 837 uport->iotype = old_iotype;
833 838 uport->regshift = old_shift;
834 839 uport->mapbase = old_mapbase;
835   - retval = uport->ops->request_port(uport);
836   - /*
837   - * If we failed to restore the old settings,
838   - * we fail like this.
839   - */
840   - if (retval)
841   - uport->type = PORT_UNKNOWN;
842 840  
843   - /*
844   - * We failed anyway.
845   - */
846   - retval = -EBUSY;
  841 + if (old_type != PORT_UNKNOWN) {
  842 + retval = uport->ops->request_port(uport);
  843 + /*
  844 + * If we failed to restore the old settings,
  845 + * we fail like this.
  846 + */
  847 + if (retval)
  848 + uport->type = PORT_UNKNOWN;
  849 +
  850 + /*
  851 + * We failed anyway.
  852 + */
  853 + retval = -EBUSY;
  854 + }
  855 +
847 856 /* Added to return the correct error -Ram Gupta */
848 857 goto exit;
849 858 }
... ... @@ -1569,12 +1578,6 @@
1569 1578 retval = -EAGAIN;
1570 1579 goto err_dec_count;
1571 1580 }
1572   -
1573   - /*
1574   - * Make sure the device is in D0 state.
1575   - */
1576   - if (port->count == 1)
1577   - uart_change_pm(state, UART_PM_STATE_ON);
1578 1581  
1579 1582 /*
1580 1583 * Start up the serial port.
drivers/tty/tty_buffer.c
... ... @@ -255,11 +255,16 @@
255 255 if (change || left < size) {
256 256 /* This is the slow path - looking for new buffers to use */
257 257 if ((n = tty_buffer_alloc(port, size)) != NULL) {
  258 + unsigned long iflags;
  259 +
258 260 n->flags = flags;
259 261 buf->tail = n;
  262 +
  263 + spin_lock_irqsave(&buf->flush_lock, iflags);
260 264 b->commit = b->used;
261   - smp_mb();
262 265 b->next = n;
  266 + spin_unlock_irqrestore(&buf->flush_lock, iflags);
  267 +
263 268 } else if (change)
264 269 size = 0;
265 270 else
... ... @@ -443,6 +448,7 @@
443 448 mutex_lock(&buf->lock);
444 449  
445 450 while (1) {
  451 + unsigned long flags;
446 452 struct tty_buffer *head = buf->head;
447 453 int count;
448 454  
449 455  
450 456  
451 457  
452 458  
... ... @@ -450,14 +456,19 @@
450 456 if (atomic_read(&buf->priority))
451 457 break;
452 458  
  459 + spin_lock_irqsave(&buf->flush_lock, flags);
453 460 count = head->commit - head->read;
454 461 if (!count) {
455   - if (head->next == NULL)
  462 + if (head->next == NULL) {
  463 + spin_unlock_irqrestore(&buf->flush_lock, flags);
456 464 break;
  465 + }
457 466 buf->head = head->next;
  467 + spin_unlock_irqrestore(&buf->flush_lock, flags);
458 468 tty_buffer_free(port, head);
459 469 continue;
460 470 }
  471 + spin_unlock_irqrestore(&buf->flush_lock, flags);
461 472  
462 473 count = receive_buf(tty, head, count);
463 474 if (!count)
... ... @@ -512,6 +523,7 @@
512 523 struct tty_bufhead *buf = &port->buf;
513 524  
514 525 mutex_init(&buf->lock);
  526 + spin_lock_init(&buf->flush_lock);
515 527 tty_buffer_reset(&buf->sentinel, 0);
516 528 buf->head = &buf->sentinel;
517 529 buf->tail = &buf->sentinel;
... ... @@ -61,6 +61,7 @@
61 61 struct tty_buffer *head; /* Queue head */
62 62 struct work_struct work;
63 63 struct mutex lock;
  64 + spinlock_t flush_lock;
64 65 atomic_t priority;
65 66 struct tty_buffer sentinel;
66 67 struct llist_head free; /* Free queue head */