Commit dc0ce181 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull tty/serial driver fixes from Greg KH:
 "Here are some small serial and vt fixes. These include:

   - 8250 driver fixes relating to dma issues

   - stm32 serial driver fix for threaded irqs

   - vc_screen bugfix for reported problems.

  All have been in linux-next for a while with no reported problems"

* tag 'tty-6.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF
  serial: 8250_dma: Fix DMA Rx rearm race
  serial: 8250_dma: Fix DMA Rx completion race
  serial: stm32: Merge hard IRQ and threaded IRQ handling into single IRQ handler
parents d3feaff4 226fae12
Loading
Loading
Loading
Loading
+17 −4
Original line number Original line Diff line number Diff line
@@ -43,15 +43,23 @@ static void __dma_rx_complete(struct uart_8250_port *p)
	struct uart_8250_dma	*dma = p->dma;
	struct uart_8250_dma	*dma = p->dma;
	struct tty_port		*tty_port = &p->port.state->port;
	struct tty_port		*tty_port = &p->port.state->port;
	struct dma_tx_state	state;
	struct dma_tx_state	state;
	enum dma_status		dma_status;
	int			count;
	int			count;


	dma->rx_running = 0;
	/*
	dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
	 * New DMA Rx can be started during the completion handler before it
	 * could acquire port's lock and it might still be ongoing. Don't to
	 * anything in such case.
	 */
	dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
	if (dma_status == DMA_IN_PROGRESS)
		return;


	count = dma->rx_size - state.residue;
	count = dma->rx_size - state.residue;


	tty_insert_flip_string(tty_port, dma->rx_buf, count);
	tty_insert_flip_string(tty_port, dma->rx_buf, count);
	p->port.icount.rx += count;
	p->port.icount.rx += count;
	dma->rx_running = 0;


	tty_flip_buffer_push(tty_port);
	tty_flip_buffer_push(tty_port);
}
}
@@ -62,9 +70,14 @@ static void dma_rx_complete(void *param)
	struct uart_8250_dma *dma = p->dma;
	struct uart_8250_dma *dma = p->dma;
	unsigned long flags;
	unsigned long flags;


	spin_lock_irqsave(&p->port.lock, flags);
	if (dma->rx_running)
		__dma_rx_complete(p);
		__dma_rx_complete(p);


	spin_lock_irqsave(&p->port.lock, flags);
	/*
	 * Cannot be combined with the previous check because __dma_rx_complete()
	 * changes dma->rx_running.
	 */
	if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR))
	if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR))
		p->dma->rx_dma(p);
		p->dma->rx_dma(p);
	spin_unlock_irqrestore(&p->port.lock, flags);
	spin_unlock_irqrestore(&p->port.lock, flags);
+5 −28
Original line number Original line Diff line number Diff line
@@ -797,25 +797,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
		spin_unlock(&port->lock);
		spin_unlock(&port->lock);
	}
	}


	if (stm32_usart_rx_dma_enabled(port))
		return IRQ_WAKE_THREAD;
	else
		return IRQ_HANDLED;
}

static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr)
{
	struct uart_port *port = ptr;
	struct tty_port *tport = &port->state->port;
	struct stm32_port *stm32_port = to_stm32_port(port);
	unsigned int size;
	unsigned long flags;

	/* Receiver timeout irq for DMA RX */
	/* Receiver timeout irq for DMA RX */
	if (!stm32_port->throttled) {
	if (stm32_usart_rx_dma_enabled(port) && !stm32_port->throttled) {
		spin_lock_irqsave(&port->lock, flags);
		spin_lock(&port->lock);
		size = stm32_usart_receive_chars(port, false);
		size = stm32_usart_receive_chars(port, false);
		uart_unlock_and_check_sysrq_irqrestore(port, flags);
		uart_unlock_and_check_sysrq(port);
		if (size)
		if (size)
			tty_flip_buffer_push(tport);
			tty_flip_buffer_push(tport);
	}
	}
@@ -1015,10 +1001,8 @@ static int stm32_usart_startup(struct uart_port *port)
	u32 val;
	u32 val;
	int ret;
	int ret;


	ret = request_threaded_irq(port->irq, stm32_usart_interrupt,
	ret = request_irq(port->irq, stm32_usart_interrupt,
				   stm32_usart_threaded_interrupt,
			  IRQF_NO_SUSPEND, name, port);
				   IRQF_ONESHOT | IRQF_NO_SUSPEND,
				   name, port);
	if (ret)
	if (ret)
		return ret;
		return ret;


@@ -1601,13 +1585,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
	struct dma_slave_config config;
	struct dma_slave_config config;
	int ret;
	int ret;


	/*
	 * Using DMA and threaded handler for the console could lead to
	 * deadlocks.
	 */
	if (uart_console(port))
		return -ENODEV;

	stm32port->rx_buf = dma_alloc_coherent(dev, RX_BUF_L,
	stm32port->rx_buf = dma_alloc_coherent(dev, RX_BUF_L,
					       &stm32port->rx_dma_buf,
					       &stm32port->rx_dma_buf,
					       GFP_KERNEL);
					       GFP_KERNEL);
+5 −4
Original line number Original line Diff line number Diff line
@@ -386,10 +386,6 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)


	uni_mode = use_unicode(inode);
	uni_mode = use_unicode(inode);
	attr = use_attributes(inode);
	attr = use_attributes(inode);
	ret = -ENXIO;
	vc = vcs_vc(inode, &viewed);
	if (!vc)
		goto unlock_out;


	ret = -EINVAL;
	ret = -EINVAL;
	if (pos < 0)
	if (pos < 0)
@@ -407,6 +403,11 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
		unsigned int this_round, skip = 0;
		unsigned int this_round, skip = 0;
		int size;
		int size;


		ret = -ENXIO;
		vc = vcs_vc(inode, &viewed);
		if (!vc)
			goto unlock_out;

		/* Check whether we are above size each round,
		/* Check whether we are above size each round,
		 * as copy_to_user at the end of this loop
		 * as copy_to_user at the end of this loop
		 * could sleep.
		 * could sleep.