serial8250_rx_chars() must be called from interrupt context and with the port lock held. The port lock is released temporarily within that function to call tty_flip_buffer_push(). However, there may be other drivers that need to synchronize the tty_flip_buffer_push() call within serial8250_rx_chars() with other contexts. Since the port lock cannot be used for this synchronization, an optional spinlock argument is added. If non-NULL, this will be locked during the tty_flip_buffer_push() call. Signed-off-by: John Ogness <john.ogness@xxxxxxxxxxxxx> --- patch against next-20160122 drivers/tty/serial/8250/8250_fsl.c | 2 +- drivers/tty/serial/8250/8250_omap.c | 2 +- drivers/tty/serial/8250/8250_port.c | 9 +++++++-- include/linux/serial_8250.h | 3 ++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index 910bfee..790868d 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -49,7 +49,7 @@ int fsl8250_handle_irq(struct uart_port *port) lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR); if (lsr & (UART_LSR_DR | UART_LSR_BI)) - lsr = serial8250_rx_chars(up, lsr); + lsr = serial8250_rx_chars(up, lsr, NULL); serial8250_modem_status(up); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index a2c0734..6cf3b4f 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1024,7 +1024,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) dma_err = omap_8250_rx_dma(up, iir); if (dma_err) { - status = serial8250_rx_chars(up, status); + status = serial8250_rx_chars(up, status, NULL); omap_8250_rx_dma(up, 0); } } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 8d262bc..e838115 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1418,7 +1418,8 @@ static void serial8250_enable_ms(struct uart_port *port) * by this Rx routine. */ unsigned char -serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) +serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr, + spinlock_t *flip_lock) { struct uart_port *port = &up->port; unsigned char ch; @@ -1485,7 +1486,11 @@ ignore_char: lsr = serial_in(up, UART_LSR); } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0)); spin_unlock(&port->lock); + if (flip_lock) + spin_lock(flip_lock); tty_flip_buffer_push(&port->state->port); + if (flip_lock) + spin_unlock(flip_lock); spin_lock(&port->lock); return lsr; } @@ -1591,7 +1596,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) dma_err = up->dma->rx_dma(up, iir); if (!up->dma || dma_err) - status = serial8250_rx_chars(up, status); + status = serial8250_rx_chars(up, status, NULL); } serial8250_modem_status(up); if ((!up->dma || (up->dma && up->dma->tx_err)) && diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index faa0e03..9c814e3 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -147,7 +147,8 @@ extern void serial8250_do_pm(struct uart_port *port, unsigned int state, extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl); extern int fsl8250_handle_irq(struct uart_port *port); int serial8250_handle_irq(struct uart_port *port, unsigned int iir); -unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr); +unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr, + spinlock_t *flip_lock); void serial8250_tx_chars(struct uart_8250_port *up); unsigned int serial8250_modem_status(struct uart_8250_port *up); void serial8250_init_port(struct uart_8250_port *up); -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html