Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a8d70698 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents d0c15ad7 7deb39ed
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1520,7 +1520,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
			status = serial8250_rx_chars(up, status);
	}
	serial8250_modem_status(up);
	if (status & UART_LSR_THRE)
	if (!up->dma && (status & UART_LSR_THRE))
		serial8250_tx_chars(up);

	spin_unlock_irqrestore(&port->lock, flags);
+7 −2
Original line number Diff line number Diff line
@@ -20,12 +20,15 @@ static void __dma_tx_complete(void *param)
	struct uart_8250_port	*p = param;
	struct uart_8250_dma	*dma = p->dma;
	struct circ_buf		*xmit = &p->port.state->xmit;

	dma->tx_running = 0;
	unsigned long	flags;

	dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
				UART_XMIT_SIZE, DMA_TO_DEVICE);

	spin_lock_irqsave(&p->port.lock, flags);

	dma->tx_running = 0;

	xmit->tail += dma->tx_size;
	xmit->tail &= UART_XMIT_SIZE - 1;
	p->port.icount.tx += dma->tx_size;
@@ -35,6 +38,8 @@ static void __dma_tx_complete(void *param)

	if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port))
		serial8250_tx_dma(p);

	spin_unlock_irqrestore(&p->port.lock, flags);
}

static void __dma_rx_complete(void *param)
+12 −11
Original line number Diff line number Diff line
@@ -1446,8 +1446,8 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port)
static void s3c24xx_serial_put_poll_char(struct uart_port *port,
		unsigned char c)
{
	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
	unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
	unsigned int ucon = rd_regl(port, S3C2410_UCON);

	/* not possible to xmit on unconfigured port */
	if (!s3c24xx_port_configured(ucon))
@@ -1455,7 +1455,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,

	while (!s3c24xx_serial_console_txrdy(port, ufcon))
		cpu_relax();
	wr_regb(cons_uart, S3C2410_UTXH, c);
	wr_regb(port, S3C2410_UTXH, c);
}

#endif /* CONFIG_CONSOLE_POLL */
@@ -1463,22 +1463,23 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
static void
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
{
	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);

	/* not possible to xmit on unconfigured port */
	if (!s3c24xx_port_configured(ucon))
		return;
	unsigned int ufcon = rd_regl(port, S3C2410_UFCON);

	while (!s3c24xx_serial_console_txrdy(port, ufcon))
		barrier();
	wr_regb(cons_uart, S3C2410_UTXH, ch);
		cpu_relax();
	wr_regb(port, S3C2410_UTXH, ch);
}

static void
s3c24xx_serial_console_write(struct console *co, const char *s,
			     unsigned int count)
{
	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);

	/* not possible to xmit on unconfigured port */
	if (!s3c24xx_port_configured(ucon))
		return;

	uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
}

+21 −18
Original line number Diff line number Diff line
@@ -136,6 +136,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
	if (uport->type == PORT_UNKNOWN)
		return 1;

	/*
	 * Make sure the device is in D0 state.
	 */
	uart_change_pm(state, UART_PM_STATE_ON);

	/*
	 * Initialise and allocate the transmit and temporary
	 * buffer.
@@ -825,13 +830,15 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
		 * If we fail to request resources for the
		 * new port, try to restore the old settings.
		 */
		if (retval && old_type != PORT_UNKNOWN) {
		if (retval) {
			uport->iobase = old_iobase;
			uport->type = old_type;
			uport->hub6 = old_hub6;
			uport->iotype = old_iotype;
			uport->regshift = old_shift;
			uport->mapbase = old_mapbase;

			if (old_type != PORT_UNKNOWN) {
				retval = uport->ops->request_port(uport);
				/*
				 * If we failed to restore the old settings,
@@ -844,6 +851,8 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
				 * We failed anyway.
				 */
				retval = -EBUSY;
			}

			/* Added to return the correct error -Ram Gupta */
			goto exit;
		}
@@ -1570,12 +1579,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
		goto err_dec_count;
	}

	/*
	 * Make sure the device is in D0 state.
	 */
	if (port->count == 1)
		uart_change_pm(state, UART_PM_STATE_ON);

	/*
	 * Start up the serial port.
	 */
+14 −2
Original line number Diff line number Diff line
@@ -255,11 +255,16 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
	if (change || left < size) {
		/* This is the slow path - looking for new buffers to use */
		if ((n = tty_buffer_alloc(port, size)) != NULL) {
			unsigned long iflags;

			n->flags = flags;
			buf->tail = n;

			spin_lock_irqsave(&buf->flush_lock, iflags);
			b->commit = b->used;
			smp_mb();
			b->next = n;
			spin_unlock_irqrestore(&buf->flush_lock, iflags);

		} else if (change)
			size = 0;
		else
@@ -443,6 +448,7 @@ static void flush_to_ldisc(struct work_struct *work)
	mutex_lock(&buf->lock);

	while (1) {
		unsigned long flags;
		struct tty_buffer *head = buf->head;
		int count;

@@ -450,14 +456,19 @@ static void flush_to_ldisc(struct work_struct *work)
		if (atomic_read(&buf->priority))
			break;

		spin_lock_irqsave(&buf->flush_lock, flags);
		count = head->commit - head->read;
		if (!count) {
			if (head->next == NULL)
			if (head->next == NULL) {
				spin_unlock_irqrestore(&buf->flush_lock, flags);
				break;
			}
			buf->head = head->next;
			spin_unlock_irqrestore(&buf->flush_lock, flags);
			tty_buffer_free(port, head);
			continue;
		}
		spin_unlock_irqrestore(&buf->flush_lock, flags);

		count = receive_buf(tty, head, count);
		if (!count)
@@ -512,6 +523,7 @@ void tty_buffer_init(struct tty_port *port)
	struct tty_bufhead *buf = &port->buf;

	mutex_init(&buf->lock);
	spin_lock_init(&buf->flush_lock);
	tty_buffer_reset(&buf->sentinel, 0);
	buf->head = &buf->sentinel;
	buf->tail = &buf->sentinel;
Loading