Commit dc0ce181 authored by Linus Torvalds's avatar Linus Torvalds

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

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
...@@ -43,15 +43,23 @@ static void __dma_rx_complete(struct uart_8250_port *p) ...@@ -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) ...@@ -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;
__dma_rx_complete(p);
spin_lock_irqsave(&p->port.lock, flags); spin_lock_irqsave(&p->port.lock, flags);
if (dma->rx_running)
__dma_rx_complete(p);
/*
* 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);
......
...@@ -797,25 +797,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) ...@@ -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) ...@@ -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, ...@@ -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);
......
...@@ -386,10 +386,6 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ...@@ -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) ...@@ -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.
......
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