lkml.org 
[lkml]   [2019]   [Mar]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.0 148/238] serial: uartps: Fix stuck ISR if RX disabled with non-empty FIFO
    Date
    5.0-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Anssi Hannula <anssi.hannula@bitwise.fi>

    commit 7abab1605139bc41442864c18f9573440f7ca105 upstream.

    If RX is disabled while there are still unprocessed bytes in RX FIFO,
    cdns_uart_handle_rx() called from interrupt handler will get stuck in
    the receive loop as read bytes will not get removed from the RX FIFO
    and CDNS_UART_SR_RXEMPTY bit will never get set.

    Avoid the stuck handler by checking first if RX is disabled. port->lock
    protects against race with RX-disabling functions.

    This HW behavior was mentioned by Nathan Rossi in 43e98facc4a3 ("tty:
    xuartps: Fix RX hang, and TX corruption in termios call") which fixed a
    similar issue in cdns_uart_set_termios().
    The behavior can also be easily verified by e.g. setting
    CDNS_UART_CR_RX_DIS at the beginning of cdns_uart_handle_rx() - the
    following loop will then get stuck.

    Resetting the FIFO using RXRST would not set RXEMPTY either so simply
    issuing a reset after RX-disable would not work.

    I observe this frequently on a ZynqMP board during heavy RX load at 1M
    baudrate when the reader process exits and thus RX gets disabled.

    Fixes: 61ec9016988f ("tty/serial: add support for Xilinx PS UART")
    Signed-off-by: Anssi Hannula <anssi.hannula@bitwise.fi>
    Cc: stable@vger.kernel.org
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/tty/serial/xilinx_uartps.c | 8 +++++++-
    1 file changed, 7 insertions(+), 1 deletion(-)

    --- a/drivers/tty/serial/xilinx_uartps.c
    +++ b/drivers/tty/serial/xilinx_uartps.c
    @@ -364,7 +364,13 @@ static irqreturn_t cdns_uart_isr(int irq
    cdns_uart_handle_tx(dev_id);
    isrstatus &= ~CDNS_UART_IXR_TXEMPTY;
    }
    - if (isrstatus & CDNS_UART_IXR_RXMASK)
    +
    + /*
    + * Skip RX processing if RX is disabled as RXEMPTY will never be set
    + * as read bytes will not be removed from the FIFO.
    + */
    + if (isrstatus & CDNS_UART_IXR_RXMASK &&
    + !(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS))
    cdns_uart_handle_rx(dev_id, isrstatus);

    spin_unlock(&port->lock);

    \
     
     \ /
      Last update: 2019-03-22 13:39    [W:3.169 / U:0.512 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site