Commit a8d706986c5ee65354d8ddd88fe2dadfd2184991
Exists in
master
and in
13 other branches
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; |
include/linux/tty.h