diff mbox

[2/2] xen/ns16550: Fix ISR lockup on Designware 8250 (H5)

Message ID 1505828334-29109-3-git-send-email-awais.masood@vadion.com (mailing list archive)
State New, archived
Headers show

Commit Message

Awais Masood Sept. 19, 2017, 1:38 p.m. UTC
On H5 (Orange Pi PC2) serial driver goes into an infinite loop as soon
as interrupts are enabled. The reason being a residual "busy detect"
interrupt. Since the condition UART_IIR_NOINT is not true, we'll remain
in this while loop forever.

A check has been added to detect "busy detect" interrupt condition and
UART_USR register is read to clear the condition. Conditonal for
dw_usr_busy ensures this hw quirk fix affects only designware uarts.

The check during ns16550_setup_preirq call does not help on H5 because
its called before LCR is set and if the busy condition appears again
during subsequent LCR writes, we end up in this situation.

Tested on Orange Pi PC2

Signed-off-by: Awais Masood <awais.masood@vadion.com>
---
 xen/drivers/char/ns16550.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Comments

Jan Beulich Sept. 19, 2017, 1:49 p.m. UTC | #1
>>> On 19.09.17 at 15:38, <awais.masood@vadion.com> wrote:
> --- a/xen/drivers/char/ns16550.c
> +++ b/xen/drivers/char/ns16550.c
> @@ -521,6 +521,18 @@ static void ns16550_interrupt(
>              serial_tx_interrupt(port, regs);
>          if ( lsr & UART_LSR_DR )
>              serial_rx_interrupt(port, regs);
> +        if ( uart->dw_usr_bsy &&
> +             (ns_read_reg(uart, UART_IIR) & UART_IIR_BSY) == UART_IIR_BSY )
> +        {
> +            /* If DesignWare 8250 UART became busy again when LCR was written
> +             * earlier, it can raise a "busy detect" again.
> +             * Read the UART Status Register to clear this state or we'll end up
> +             * in an infinte loop because UART_IIR_NOINT is not true.
> +             * Placing this check in setup_preirq after LCR write does not work
> +             * probably due to a delayed interrupt.
> +             */
> +            ns_read_reg(uart, UART_USR);
> +        }

This same code already exists in ns16550_setup_preirq() - please
introduce a helper function. It would also help if you referred to
the commit introducing that other instance of the code, explaining
why what was done there was not enough (because pretty clearly
the author must have assumed that change to be sufficient).

Jan
diff mbox

Patch

diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index 6ab5ec3..6630720 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -521,6 +521,18 @@  static void ns16550_interrupt(
             serial_tx_interrupt(port, regs);
         if ( lsr & UART_LSR_DR )
             serial_rx_interrupt(port, regs);
+        if ( uart->dw_usr_bsy &&
+             (ns_read_reg(uart, UART_IIR) & UART_IIR_BSY) == UART_IIR_BSY )
+        {
+            /* If DesignWare 8250 UART became busy again when LCR was written
+             * earlier, it can raise a "busy detect" again.
+             * Read the UART Status Register to clear this state or we'll end up
+             * in an infinte loop because UART_IIR_NOINT is not true.
+             * Placing this check in setup_preirq after LCR write does not work
+             * probably due to a delayed interrupt.
+             */
+            ns_read_reg(uart, UART_USR);
+        }
     }
 }