diff mbox

8250: add workaround for MPC8[356]xx UART break IRQ storm

Message ID 1267212301-26851-1-git-send-email-paul.gortmaker@windriver.com (mailing list archive)
State Superseded
Delegated to: Kumar Gala
Headers show

Commit Message

Paul Gortmaker Feb. 26, 2010, 7:25 p.m. UTC
Sending a break on the SOC UARTs found in some MPC83xx/85xx/86xx
chips seems to cause a short lived IRQ storm (/proc/interrupts
typically shows somewhere between 300 and 1500 events).  Unfortunately
this renders SysRQ over the serial console completely inoperable.
Testing with obvious things like ACKing the event doesn't seem to
change anything vs. a completely dumb approach of just ignoring
it and waiting for it to stop, so that is what is implemented here.

Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---

This is a refresh of a patch I'd done earlier -- I've tried to make
the bug support as generic as possible to minimize having board
specific ifdef crap in 8250.c -- any suggestions on how to further
improve it are welcome.

 drivers/serial/8250.c      |    6 ++++++
 drivers/serial/8250.h      |   20 ++++++++++++++++++++
 drivers/serial/Kconfig     |   14 ++++++++++++++
 include/linux/serial_reg.h |    2 ++
 4 files changed, 42 insertions(+), 0 deletions(-)

Comments

vb March 1, 2010, 11:03 p.m. UTC | #1
sounds very much like this issue:

http://linux.derkeiler.com/Mailing-Lists/Kernel/2010-02/msg09470.html

(interrupt storm on the second port which is hit with breaks).

It's not the uart driver problem per se, the below fixes it:

*** linux/drivers/serial/serial_core.c#1        Wed Feb 24 17:46:22 2010
---  linux/drivers/serial/serial_core.c#2        Mon Mar  1 15:00:29 2010
***************
*** 622,632 ****
        struct uart_port *port = state->port;

        if (I_IXOFF(tty)) {
                if (port->x_char)
                        port->x_char = 0;
!               else
                        uart_send_xchar(tty, START_CHAR(tty));
        }

        if (tty->termios->c_cflag & CRTSCTS)
                uart_set_mctrl(port, TIOCM_RTS);
--- 622,632 ----
        struct uart_port *port = state->port;

        if (I_IXOFF(tty)) {
                if (port->x_char)
                        port->x_char = 0;
!               else if (!(tty->flags & (1 << TTY_IO_ERROR)))
                        uart_send_xchar(tty, START_CHAR(tty));
        }

        if (tty->termios->c_cflag & CRTSCTS)
                uart_set_mctrl(port, TIOCM_RTS);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I did not get to trying to submit it, but it sure gets rid o the storm.

cheers,
/vb

On Fri, Feb 26, 2010 at 11:25 AM, Paul Gortmaker
<paul.gortmaker@windriver.com> wrote:
> Sending a break on the SOC UARTs found in some MPC83xx/85xx/86xx
> chips seems to cause a short lived IRQ storm (/proc/interrupts
> typically shows somewhere between 300 and 1500 events).  Unfortunately
> this renders SysRQ over the serial console completely inoperable.
> Testing with obvious things like ACKing the event doesn't seem to
> change anything vs. a completely dumb approach of just ignoring
> it and waiting for it to stop, so that is what is implemented here.
>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
>
> This is a refresh of a patch I'd done earlier -- I've tried to make
> the bug support as generic as possible to minimize having board
> specific ifdef crap in 8250.c -- any suggestions on how to further
> improve it are welcome.
>
>  drivers/serial/8250.c      |    6 ++++++
>  drivers/serial/8250.h      |   20 ++++++++++++++++++++
>  drivers/serial/Kconfig     |   14 ++++++++++++++
>  include/linux/serial_reg.h |    2 ++
>  4 files changed, 42 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
> index e9b15c3..850b0e9 100644
> --- a/drivers/serial/8250.c
> +++ b/drivers/serial/8250.c
> @@ -1531,6 +1531,11 @@ static void serial8250_handle_port(struct uart_8250_port *up)
>
>        status = serial_inp(up, UART_LSR);
>
> +       if ((up->bugs & UART_BUG_PPC) && (status == UART_LSR_RFE_ERROR_BITS)) {
> +               spin_unlock_irqrestore(&up->port.lock, flags);
> +               return;
> +       }
> +
>        DEBUG_INTR("status = %x...", status);
>
>        if (status & (UART_LSR_DR | UART_LSR_BI))
> @@ -1948,6 +1953,7 @@ static int serial8250_startup(struct uart_port *port)
>
>        up->capabilities = uart_config[up->port.type].flags;
>        up->mcr = 0;
> +       up->bugs |= UART_KNOWN_BUGS;
>
>        if (up->port.iotype != up->cur_iotype)
>                set_io_from_upio(port);
> diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
> index 6e19ea3..2074ce1 100644
> --- a/drivers/serial/8250.h
> +++ b/drivers/serial/8250.h
> @@ -49,6 +49,7 @@ struct serial8250_config {
>  #define UART_BUG_TXEN  (1 << 1)        /* UART has buggy TX IIR status */
>  #define UART_BUG_NOMSR (1 << 2)        /* UART has buggy MSR status bits (Au1x00) */
>  #define UART_BUG_THRE  (1 << 3)        /* UART has buggy THRE reassertion */
> +#define UART_BUG_PPC   (1 << 4)        /* UART has buggy PPC break IRQ storm */
>
>  #define PROBE_RSA      (1 << 0)
>  #define PROBE_ANY      (~0)
> @@ -78,3 +79,22 @@ struct serial8250_config {
>  #else
>  #define ALPHA_KLUDGE_MCR 0
>  #endif
> +
> +/*
> + * The following UART bugs are currently dynamically detected and not
> + * required to be contingent on any particular compile time options.
> + */
> +#define HAS_BUG_QUOT   0       /* assign UART_BUG_QUOT to enable */
> +#define HAS_BUG_TXEN   0       /* assign UART_BUG_TXEN to enable */
> +#define HAS_BUG_NOMSR  0       /* assign UART_BUG_NOMSR to enable */
> +#define HAS_BUG_THRE   0       /* assign UART_BUG_THRE to enable */
> +
> +#ifdef CONFIG_SERIAL_8250_PPC_BUG
> +#define HAS_BUG_PPC    UART_BUG_PPC
> +#else
> +#define HAS_BUG_PPC    0
> +#endif
> +
> +#define UART_KNOWN_BUGS (HAS_BUG_QUOT | HAS_BUG_TXEN | HAS_BUG_NOMSR | \
> +                       HAS_BUG_THRE | HAS_BUG_PPC)
> +
> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
> index 9ff47db..e01a411 100644
> --- a/drivers/serial/Kconfig
> +++ b/drivers/serial/Kconfig
> @@ -70,6 +70,20 @@ config SERIAL_8250_CONSOLE
>
>          If unsure, say N.
>
> +config SERIAL_8250_PPC_BUG
> +       bool "Fix 8250/16550 to handle IRQ storm after receipt of a break"
> +       depends on SERIAL_8250 && PPC32
> +       ---help---
> +         If you say Y here, addional checks will be added in the handling of
> +         interrupts on the serial ports which will prevent ill effects of
> +         an interrupt storm triggered by a break on the serial line. Without
> +         this enabled, a Sysrq via the serial console can be unusable on
> +         some systems.
> +
> +         This is commonly observed on PPC32 MPC83xx/85xx/86xx based boards.
> +
> +         If unsure, say N.
> +
>  config FIX_EARLYCON_MEM
>        bool
>        depends on X86
> diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
> index cf9327c..010174f 100644
> --- a/include/linux/serial_reg.h
> +++ b/include/linux/serial_reg.h
> @@ -111,6 +111,7 @@
>  #define UART_MCR_DTR           0x01 /* DTR complement */
>
>  #define UART_LSR       5       /* In:  Line Status Register */
> +#define UART_LSR_RFE           0x80 /* Rx FIFO Error (BE, FE, or PE) */
>  #define UART_LSR_TEMT          0x40 /* Transmitter empty */
>  #define UART_LSR_THRE          0x20 /* Transmit-hold-register empty */
>  #define UART_LSR_BI            0x10 /* Break interrupt indicator */
> @@ -119,6 +120,7 @@
>  #define UART_LSR_OE            0x02 /* Overrun error indicator */
>  #define UART_LSR_DR            0x01 /* Receiver data ready */
>  #define UART_LSR_BRK_ERROR_BITS        0x1E /* BI, FE, PE, OE bits */
> +#define UART_LSR_RFE_ERROR_BITS        0xF1 /* RFE, TEMT, THRE, BI, DR bits */
>
>  #define UART_MSR       6       /* In:  Modem Status Register */
>  #define UART_MSR_DCD           0x80 /* Data Carrier Detect */
> --
> 1.6.5.2
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
Paul Gortmaker March 2, 2010, 4:27 p.m. UTC | #2
On 10-03-01 06:03 PM, vb@vsbe.com wrote:
> sounds very much like this issue:
> 
> http://linux.derkeiler.com/Mailing-Lists/Kernel/2010-02/msg09470.html

Thanks for the link.

> 
> (interrupt storm on the second port which is hit with breaks).
> 
> It's not the uart driver problem per se, the below fixes it:

Actually, it is a uart *hardware* problem -- see in this same
thread where Scott Wood described an errata, and when I
implemented his interpretation of what the fix should look
like, things just worked.  You might want to try out that patch
and see if it helps you, since from the link above, I see you
are also on a powerpc board.

Paul.

> 
> *** linux/drivers/serial/serial_core.c#1        Wed Feb 24 17:46:22 2010
> ---  linux/drivers/serial/serial_core.c#2        Mon Mar  1 15:00:29 2010
> ***************
> *** 622,632 ****
>          struct uart_port *port = state->port;
> 
>          if (I_IXOFF(tty)) {
>                  if (port->x_char)
>                          port->x_char = 0;
> !               else
>                          uart_send_xchar(tty, START_CHAR(tty));
>          }
> 
>          if (tty->termios->c_cflag&  CRTSCTS)
>                  uart_set_mctrl(port, TIOCM_RTS);
> --- 622,632 ----
>          struct uart_port *port = state->port;
> 
>          if (I_IXOFF(tty)) {
>                  if (port->x_char)
>                          port->x_char = 0;
> !               else if (!(tty->flags&  (1<<  TTY_IO_ERROR)))
>                          uart_send_xchar(tty, START_CHAR(tty));
>          }
> 
>          if (tty->termios->c_cflag&  CRTSCTS)
>                  uart_set_mctrl(port, TIOCM_RTS);
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> I did not get to trying to submit it, but it sure gets rid o the storm.
> 
> cheers,
> /vb
> 
> On Fri, Feb 26, 2010 at 11:25 AM, Paul Gortmaker
> <paul.gortmaker@windriver.com>  wrote:
>> Sending a break on the SOC UARTs found in some MPC83xx/85xx/86xx
>> chips seems to cause a short lived IRQ storm (/proc/interrupts
>> typically shows somewhere between 300 and 1500 events).  Unfortunately
>> this renders SysRQ over the serial console completely inoperable.
>> Testing with obvious things like ACKing the event doesn't seem to
>> change anything vs. a completely dumb approach of just ignoring
>> it and waiting for it to stop, so that is what is implemented here.
>>
>> Signed-off-by: Paul Gortmaker<paul.gortmaker@windriver.com>
>> ---
>>
>> This is a refresh of a patch I'd done earlier -- I've tried to make
>> the bug support as generic as possible to minimize having board
>> specific ifdef crap in 8250.c -- any suggestions on how to further
>> improve it are welcome.
>>
>>   drivers/serial/8250.c      |    6 ++++++
>>   drivers/serial/8250.h      |   20 ++++++++++++++++++++
>>   drivers/serial/Kconfig     |   14 ++++++++++++++
>>   include/linux/serial_reg.h |    2 ++
>>   4 files changed, 42 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
>> index e9b15c3..850b0e9 100644
>> --- a/drivers/serial/8250.c
>> +++ b/drivers/serial/8250.c
>> @@ -1531,6 +1531,11 @@ static void serial8250_handle_port(struct uart_8250_port *up)
>>
>>         status = serial_inp(up, UART_LSR);
>>
>> +       if ((up->bugs&  UART_BUG_PPC)&&  (status == UART_LSR_RFE_ERROR_BITS)) {
>> +               spin_unlock_irqrestore(&up->port.lock, flags);
>> +               return;
>> +       }
>> +
>>         DEBUG_INTR("status = %x...", status);
>>
>>         if (status&  (UART_LSR_DR | UART_LSR_BI))
>> @@ -1948,6 +1953,7 @@ static int serial8250_startup(struct uart_port *port)
>>
>>         up->capabilities = uart_config[up->port.type].flags;
>>         up->mcr = 0;
>> +       up->bugs |= UART_KNOWN_BUGS;
>>
>>         if (up->port.iotype != up->cur_iotype)
>>                 set_io_from_upio(port);
>> diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
>> index 6e19ea3..2074ce1 100644
>> --- a/drivers/serial/8250.h
>> +++ b/drivers/serial/8250.h
>> @@ -49,6 +49,7 @@ struct serial8250_config {
>>   #define UART_BUG_TXEN  (1<<  1)        /* UART has buggy TX IIR status */
>>   #define UART_BUG_NOMSR (1<<  2)        /* UART has buggy MSR status bits (Au1x00) */
>>   #define UART_BUG_THRE  (1<<  3)        /* UART has buggy THRE reassertion */
>> +#define UART_BUG_PPC   (1<<  4)        /* UART has buggy PPC break IRQ storm */
>>
>>   #define PROBE_RSA      (1<<  0)
>>   #define PROBE_ANY      (~0)
>> @@ -78,3 +79,22 @@ struct serial8250_config {
>>   #else
>>   #define ALPHA_KLUDGE_MCR 0
>>   #endif
>> +
>> +/*
>> + * The following UART bugs are currently dynamically detected and not
>> + * required to be contingent on any particular compile time options.
>> + */
>> +#define HAS_BUG_QUOT   0       /* assign UART_BUG_QUOT to enable */
>> +#define HAS_BUG_TXEN   0       /* assign UART_BUG_TXEN to enable */
>> +#define HAS_BUG_NOMSR  0       /* assign UART_BUG_NOMSR to enable */
>> +#define HAS_BUG_THRE   0       /* assign UART_BUG_THRE to enable */
>> +
>> +#ifdef CONFIG_SERIAL_8250_PPC_BUG
>> +#define HAS_BUG_PPC    UART_BUG_PPC
>> +#else
>> +#define HAS_BUG_PPC    0
>> +#endif
>> +
>> +#define UART_KNOWN_BUGS (HAS_BUG_QUOT | HAS_BUG_TXEN | HAS_BUG_NOMSR | \
>> +                       HAS_BUG_THRE | HAS_BUG_PPC)
>> +
>> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
>> index 9ff47db..e01a411 100644
>> --- a/drivers/serial/Kconfig
>> +++ b/drivers/serial/Kconfig
>> @@ -70,6 +70,20 @@ config SERIAL_8250_CONSOLE
>>
>>           If unsure, say N.
>>
>> +config SERIAL_8250_PPC_BUG
>> +       bool "Fix 8250/16550 to handle IRQ storm after receipt of a break"
>> +       depends on SERIAL_8250&&  PPC32
>> +       ---help---
>> +         If you say Y here, addional checks will be added in the handling of
>> +         interrupts on the serial ports which will prevent ill effects of
>> +         an interrupt storm triggered by a break on the serial line. Without
>> +         this enabled, a Sysrq via the serial console can be unusable on
>> +         some systems.
>> +
>> +         This is commonly observed on PPC32 MPC83xx/85xx/86xx based boards.
>> +
>> +         If unsure, say N.
>> +
>>   config FIX_EARLYCON_MEM
>>         bool
>>         depends on X86
>> diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
>> index cf9327c..010174f 100644
>> --- a/include/linux/serial_reg.h
>> +++ b/include/linux/serial_reg.h
>> @@ -111,6 +111,7 @@
>>   #define UART_MCR_DTR           0x01 /* DTR complement */
>>
>>   #define UART_LSR       5       /* In:  Line Status Register */
>> +#define UART_LSR_RFE           0x80 /* Rx FIFO Error (BE, FE, or PE) */
>>   #define UART_LSR_TEMT          0x40 /* Transmitter empty */
>>   #define UART_LSR_THRE          0x20 /* Transmit-hold-register empty */
>>   #define UART_LSR_BI            0x10 /* Break interrupt indicator */
>> @@ -119,6 +120,7 @@
>>   #define UART_LSR_OE            0x02 /* Overrun error indicator */
>>   #define UART_LSR_DR            0x01 /* Receiver data ready */
>>   #define UART_LSR_BRK_ERROR_BITS        0x1E /* BI, FE, PE, OE bits */
>> +#define UART_LSR_RFE_ERROR_BITS        0xF1 /* RFE, TEMT, THRE, BI, DR bits */
>>
>>   #define UART_MSR       6       /* In:  Modem Status Register */
>>   #define UART_MSR_DCD           0x80 /* Data Carrier Detect */
>> --
>> 1.6.5.2
>>
>> _______________________________________________
>> Linuxppc-dev mailing list
>> Linuxppc-dev@lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/linuxppc-dev
>>
vb March 2, 2010, 9:21 p.m. UTC | #3
On Tue, Mar 2, 2010 at 8:27 AM, Paul Gortmaker
<paul.gortmaker@windriver.com> wrote:
> On 10-03-01 06:03 PM, vb@vsbe.com wrote:
>> sounds very much like this issue:
>>
>> http://linux.derkeiler.com/Mailing-Lists/Kernel/2010-02/msg09470.html
>
> Thanks for the link.
>
>>
>> (interrupt storm on the second port which is hit with breaks).
>>
>> It's not the uart driver problem per se, the below fixes it:
>
> Actually, it is a uart *hardware* problem -- see in this same
> thread where Scott Wood described an errata, and when I
> implemented his interpretation of what the fix should look
> like, things just worked.  You might want to try out that patch
> and see if it helps you, since from the link above, I see you
> are also on a powerpc board.
>
> Paul.
>

yeah, I was not aware of the hardware bug you are describing, it's
just the scenario I encountered is very similar: the serial interface
is flooded with breaks, after a while the prot generates an IRQ storm.
But the storm happens only after the port gets shut down (by getty in
my case).

In my case this behavior is due to a SW bug, you might be hitting the
HW problem, I have not seen it yet,

cheers,
/vb


>>
>> *** linux/drivers/serial/serial_core.c#1        Wed Feb 24 17:46:22 2010
>> ---  linux/drivers/serial/serial_core.c#2        Mon Mar  1 15:00:29 2010
>> ***************
>> *** 622,632 ****
>>          struct uart_port *port = state->port;
>>
>>          if (I_IXOFF(tty)) {
>>                  if (port->x_char)
>>                          port->x_char = 0;
>> !               else
>>                          uart_send_xchar(tty, START_CHAR(tty));
>>          }
>>
>>          if (tty->termios->c_cflag&  CRTSCTS)
>>                  uart_set_mctrl(port, TIOCM_RTS);
>> --- 622,632 ----
>>          struct uart_port *port = state->port;
>>
>>          if (I_IXOFF(tty)) {
>>                  if (port->x_char)
>>                          port->x_char = 0;
>> !               else if (!(tty->flags&  (1<<  TTY_IO_ERROR)))
>>                          uart_send_xchar(tty, START_CHAR(tty));
>>          }
>>
>>          if (tty->termios->c_cflag&  CRTSCTS)
>>                  uart_set_mctrl(port, TIOCM_RTS);
>> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>
>> I did not get to trying to submit it, but it sure gets rid o the storm.
>>
>> cheers,
>> /vb
>>
>> On Fri, Feb 26, 2010 at 11:25 AM, Paul Gortmaker
>> <paul.gortmaker@windriver.com>  wrote:
>>> Sending a break on the SOC UARTs found in some MPC83xx/85xx/86xx
>>> chips seems to cause a short lived IRQ storm (/proc/interrupts
>>> typically shows somewhere between 300 and 1500 events).  Unfortunately
>>> this renders SysRQ over the serial console completely inoperable.
>>> Testing with obvious things like ACKing the event doesn't seem to
>>> change anything vs. a completely dumb approach of just ignoring
>>> it and waiting for it to stop, so that is what is implemented here.
>>>
>>> Signed-off-by: Paul Gortmaker<paul.gortmaker@windriver.com>
>>> ---
>>>
>>> This is a refresh of a patch I'd done earlier -- I've tried to make
>>> the bug support as generic as possible to minimize having board
>>> specific ifdef crap in 8250.c -- any suggestions on how to further
>>> improve it are welcome.
>>>
>>>   drivers/serial/8250.c      |    6 ++++++
>>>   drivers/serial/8250.h      |   20 ++++++++++++++++++++
>>>   drivers/serial/Kconfig     |   14 ++++++++++++++
>>>   include/linux/serial_reg.h |    2 ++
>>>   4 files changed, 42 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
>>> index e9b15c3..850b0e9 100644
>>> --- a/drivers/serial/8250.c
>>> +++ b/drivers/serial/8250.c
>>> @@ -1531,6 +1531,11 @@ static void serial8250_handle_port(struct uart_8250_port *up)
>>>
>>>         status = serial_inp(up, UART_LSR);
>>>
>>> +       if ((up->bugs&  UART_BUG_PPC)&&  (status == UART_LSR_RFE_ERROR_BITS)) {
>>> +               spin_unlock_irqrestore(&up->port.lock, flags);
>>> +               return;
>>> +       }
>>> +
>>>         DEBUG_INTR("status = %x...", status);
>>>
>>>         if (status&  (UART_LSR_DR | UART_LSR_BI))
>>> @@ -1948,6 +1953,7 @@ static int serial8250_startup(struct uart_port *port)
>>>
>>>         up->capabilities = uart_config[up->port.type].flags;
>>>         up->mcr = 0;
>>> +       up->bugs |= UART_KNOWN_BUGS;
>>>
>>>         if (up->port.iotype != up->cur_iotype)
>>>                 set_io_from_upio(port);
>>> diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
>>> index 6e19ea3..2074ce1 100644
>>> --- a/drivers/serial/8250.h
>>> +++ b/drivers/serial/8250.h
>>> @@ -49,6 +49,7 @@ struct serial8250_config {
>>>   #define UART_BUG_TXEN  (1<<  1)        /* UART has buggy TX IIR status */
>>>   #define UART_BUG_NOMSR (1<<  2)        /* UART has buggy MSR status bits (Au1x00) */
>>>   #define UART_BUG_THRE  (1<<  3)        /* UART has buggy THRE reassertion */
>>> +#define UART_BUG_PPC   (1<<  4)        /* UART has buggy PPC break IRQ storm */
>>>
>>>   #define PROBE_RSA      (1<<  0)
>>>   #define PROBE_ANY      (~0)
>>> @@ -78,3 +79,22 @@ struct serial8250_config {
>>>   #else
>>>   #define ALPHA_KLUDGE_MCR 0
>>>   #endif
>>> +
>>> +/*
>>> + * The following UART bugs are currently dynamically detected and not
>>> + * required to be contingent on any particular compile time options.
>>> + */
>>> +#define HAS_BUG_QUOT   0       /* assign UART_BUG_QUOT to enable */
>>> +#define HAS_BUG_TXEN   0       /* assign UART_BUG_TXEN to enable */
>>> +#define HAS_BUG_NOMSR  0       /* assign UART_BUG_NOMSR to enable */
>>> +#define HAS_BUG_THRE   0       /* assign UART_BUG_THRE to enable */
>>> +
>>> +#ifdef CONFIG_SERIAL_8250_PPC_BUG
>>> +#define HAS_BUG_PPC    UART_BUG_PPC
>>> +#else
>>> +#define HAS_BUG_PPC    0
>>> +#endif
>>> +
>>> +#define UART_KNOWN_BUGS (HAS_BUG_QUOT | HAS_BUG_TXEN | HAS_BUG_NOMSR | \
>>> +                       HAS_BUG_THRE | HAS_BUG_PPC)
>>> +
>>> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
>>> index 9ff47db..e01a411 100644
>>> --- a/drivers/serial/Kconfig
>>> +++ b/drivers/serial/Kconfig
>>> @@ -70,6 +70,20 @@ config SERIAL_8250_CONSOLE
>>>
>>>           If unsure, say N.
>>>
>>> +config SERIAL_8250_PPC_BUG
>>> +       bool "Fix 8250/16550 to handle IRQ storm after receipt of a break"
>>> +       depends on SERIAL_8250&&  PPC32
>>> +       ---help---
>>> +         If you say Y here, addional checks will be added in the handling of
>>> +         interrupts on the serial ports which will prevent ill effects of
>>> +         an interrupt storm triggered by a break on the serial line. Without
>>> +         this enabled, a Sysrq via the serial console can be unusable on
>>> +         some systems.
>>> +
>>> +         This is commonly observed on PPC32 MPC83xx/85xx/86xx based boards.
>>> +
>>> +         If unsure, say N.
>>> +
>>>   config FIX_EARLYCON_MEM
>>>         bool
>>>         depends on X86
>>> diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
>>> index cf9327c..010174f 100644
>>> --- a/include/linux/serial_reg.h
>>> +++ b/include/linux/serial_reg.h
>>> @@ -111,6 +111,7 @@
>>>   #define UART_MCR_DTR           0x01 /* DTR complement */
>>>
>>>   #define UART_LSR       5       /* In:  Line Status Register */
>>> +#define UART_LSR_RFE           0x80 /* Rx FIFO Error (BE, FE, or PE) */
>>>   #define UART_LSR_TEMT          0x40 /* Transmitter empty */
>>>   #define UART_LSR_THRE          0x20 /* Transmit-hold-register empty */
>>>   #define UART_LSR_BI            0x10 /* Break interrupt indicator */
>>> @@ -119,6 +120,7 @@
>>>   #define UART_LSR_OE            0x02 /* Overrun error indicator */
>>>   #define UART_LSR_DR            0x01 /* Receiver data ready */
>>>   #define UART_LSR_BRK_ERROR_BITS        0x1E /* BI, FE, PE, OE bits */
>>> +#define UART_LSR_RFE_ERROR_BITS        0xF1 /* RFE, TEMT, THRE, BI, DR bits */
>>>
>>>   #define UART_MSR       6       /* In:  Modem Status Register */
>>>   #define UART_MSR_DCD           0x80 /* Data Carrier Detect */
>>> --
>>> 1.6.5.2
>>>
>>> _______________________________________________
>>> Linuxppc-dev mailing list
>>> Linuxppc-dev@lists.ozlabs.org
>>> https://lists.ozlabs.org/listinfo/linuxppc-dev
>>>
>
>
Kumar Gala Nov. 24, 2011, 8:14 a.m. UTC | #4
On Feb 26, 2010, at 1:25 PM, Paul Gortmaker wrote:

> Sending a break on the SOC UARTs found in some MPC83xx/85xx/86xx
> chips seems to cause a short lived IRQ storm (/proc/interrupts
> typically shows somewhere between 300 and 1500 events).  Unfortunately
> this renders SysRQ over the serial console completely inoperable.
> Testing with obvious things like ACKing the event doesn't seem to
> change anything vs. a completely dumb approach of just ignoring
> it and waiting for it to stop, so that is what is implemented here.
> 
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
> 
> This is a refresh of a patch I'd done earlier -- I've tried to make
> the bug support as generic as possible to minimize having board
> specific ifdef crap in 8250.c -- any suggestions on how to further
> improve it are welcome.
> 
> drivers/serial/8250.c      |    6 ++++++
> drivers/serial/8250.h      |   20 ++++++++++++++++++++
> drivers/serial/Kconfig     |   14 ++++++++++++++
> include/linux/serial_reg.h |    2 ++
> 4 files changed, 42 insertions(+), 0 deletions(-)

Did we ever decide what to do with this or trying to get it accepted upstream?

- k
Paul Gortmaker Nov. 24, 2011, 3:26 p.m. UTC | #5
On 11-11-24 03:14 AM, Kumar Gala wrote:
> 
> On Feb 26, 2010, at 1:25 PM, Paul Gortmaker wrote:
> 
>> Sending a break on the SOC UARTs found in some MPC83xx/85xx/86xx
>> chips seems to cause a short lived IRQ storm (/proc/interrupts
>> typically shows somewhere between 300 and 1500 events).  Unfortunately
>> this renders SysRQ over the serial console completely inoperable.
>> Testing with obvious things like ACKing the event doesn't seem to
>> change anything vs. a completely dumb approach of just ignoring
>> it and waiting for it to stop, so that is what is implemented here.
>>
>> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
>> ---
>>
>> This is a refresh of a patch I'd done earlier -- I've tried to make
>> the bug support as generic as possible to minimize having board
>> specific ifdef crap in 8250.c -- any suggestions on how to further
>> improve it are welcome.
>>
>> drivers/serial/8250.c      |    6 ++++++
>> drivers/serial/8250.h      |   20 ++++++++++++++++++++
>> drivers/serial/Kconfig     |   14 ++++++++++++++
>> include/linux/serial_reg.h |    2 ++
>> 4 files changed, 42 insertions(+), 0 deletions(-)
> 
> Did we ever decide what to do with this or trying to get it accepted upstream?

That is an old version.  ScottW gave me the errata information
which allowed me to fix the problem in a cleaner way.

http://patchwork.ozlabs.org/patch/46609/

I think the above version is OK as-is; the only thing I
think we could do to improve it is to go and automatically
select the thing based on known impacted CPU types (which
could be a separate commit or commits, as various CPUs are
confirmed to have the issue.)

Paul.

> 
> - k
Kumar Gala Nov. 24, 2011, 7:07 p.m. UTC | #6
On Nov 24, 2011, at 9:26 AM, Paul Gortmaker wrote:

> On 11-11-24 03:14 AM, Kumar Gala wrote:
>> 
>> On Feb 26, 2010, at 1:25 PM, Paul Gortmaker wrote:
>> 
>>> Sending a break on the SOC UARTs found in some MPC83xx/85xx/86xx
>>> chips seems to cause a short lived IRQ storm (/proc/interrupts
>>> typically shows somewhere between 300 and 1500 events).  Unfortunately
>>> this renders SysRQ over the serial console completely inoperable.
>>> Testing with obvious things like ACKing the event doesn't seem to
>>> change anything vs. a completely dumb approach of just ignoring
>>> it and waiting for it to stop, so that is what is implemented here.
>>> 
>>> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
>>> ---
>>> 
>>> This is a refresh of a patch I'd done earlier -- I've tried to make
>>> the bug support as generic as possible to minimize having board
>>> specific ifdef crap in 8250.c -- any suggestions on how to further
>>> improve it are welcome.
>>> 
>>> drivers/serial/8250.c      |    6 ++++++
>>> drivers/serial/8250.h      |   20 ++++++++++++++++++++
>>> drivers/serial/Kconfig     |   14 ++++++++++++++
>>> include/linux/serial_reg.h |    2 ++
>>> 4 files changed, 42 insertions(+), 0 deletions(-)
>> 
>> Did we ever decide what to do with this or trying to get it accepted upstream?
> 
> That is an old version.  ScottW gave me the errata information
> which allowed me to fix the problem in a cleaner way.
> 
> http://patchwork.ozlabs.org/patch/46609/
> 
> I think the above version is OK as-is; the only thing I
> think we could do to improve it is to go and automatically
> select the thing based on known impacted CPU types (which
> could be a separate commit or commits, as various CPUs are
> confirmed to have the issue.)

Seems as if we could have ->bugs passed in via plat_serial8250_port and than we can get the info from the device tree.

- k
diff mbox

Patch

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index e9b15c3..850b0e9 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1531,6 +1531,11 @@  static void serial8250_handle_port(struct uart_8250_port *up)
 
 	status = serial_inp(up, UART_LSR);
 
+	if ((up->bugs & UART_BUG_PPC) && (status == UART_LSR_RFE_ERROR_BITS)) {
+		spin_unlock_irqrestore(&up->port.lock, flags);
+		return;
+	}
+
 	DEBUG_INTR("status = %x...", status);
 
 	if (status & (UART_LSR_DR | UART_LSR_BI))
@@ -1948,6 +1953,7 @@  static int serial8250_startup(struct uart_port *port)
 
 	up->capabilities = uart_config[up->port.type].flags;
 	up->mcr = 0;
+	up->bugs |= UART_KNOWN_BUGS;
 
 	if (up->port.iotype != up->cur_iotype)
 		set_io_from_upio(port);
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index 6e19ea3..2074ce1 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -49,6 +49,7 @@  struct serial8250_config {
 #define UART_BUG_TXEN	(1 << 1)	/* UART has buggy TX IIR status */
 #define UART_BUG_NOMSR	(1 << 2)	/* UART has buggy MSR status bits (Au1x00) */
 #define UART_BUG_THRE	(1 << 3)	/* UART has buggy THRE reassertion */
+#define UART_BUG_PPC	(1 << 4)	/* UART has buggy PPC break IRQ storm */
 
 #define PROBE_RSA	(1 << 0)
 #define PROBE_ANY	(~0)
@@ -78,3 +79,22 @@  struct serial8250_config {
 #else
 #define ALPHA_KLUDGE_MCR 0
 #endif
+
+/*
+ * The following UART bugs are currently dynamically detected and not
+ * required to be contingent on any particular compile time options.
+ */
+#define HAS_BUG_QUOT	0	/* assign UART_BUG_QUOT to enable */
+#define HAS_BUG_TXEN	0	/* assign UART_BUG_TXEN to enable */
+#define HAS_BUG_NOMSR	0	/* assign UART_BUG_NOMSR to enable */
+#define HAS_BUG_THRE	0	/* assign UART_BUG_THRE to enable */
+
+#ifdef CONFIG_SERIAL_8250_PPC_BUG
+#define HAS_BUG_PPC	UART_BUG_PPC
+#else
+#define HAS_BUG_PPC	0
+#endif
+
+#define UART_KNOWN_BUGS (HAS_BUG_QUOT | HAS_BUG_TXEN | HAS_BUG_NOMSR | \
+			HAS_BUG_THRE | HAS_BUG_PPC)
+
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 9ff47db..e01a411 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -70,6 +70,20 @@  config SERIAL_8250_CONSOLE
 
 	  If unsure, say N.
 
+config SERIAL_8250_PPC_BUG
+	bool "Fix 8250/16550 to handle IRQ storm after receipt of a break"
+	depends on SERIAL_8250 && PPC32
+	---help---
+	  If you say Y here, addional checks will be added in the handling of
+	  interrupts on the serial ports which will prevent ill effects of
+	  an interrupt storm triggered by a break on the serial line. Without
+	  this enabled, a Sysrq via the serial console can be unusable on
+	  some systems.
+
+	  This is commonly observed on PPC32 MPC83xx/85xx/86xx based boards.
+
+	  If unsure, say N.
+
 config FIX_EARLYCON_MEM
 	bool
 	depends on X86
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index cf9327c..010174f 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -111,6 +111,7 @@ 
 #define UART_MCR_DTR		0x01 /* DTR complement */
 
 #define UART_LSR	5	/* In:  Line Status Register */
+#define UART_LSR_RFE		0x80 /* Rx FIFO Error (BE, FE, or PE) */
 #define UART_LSR_TEMT		0x40 /* Transmitter empty */
 #define UART_LSR_THRE		0x20 /* Transmit-hold-register empty */
 #define UART_LSR_BI		0x10 /* Break interrupt indicator */
@@ -119,6 +120,7 @@ 
 #define UART_LSR_OE		0x02 /* Overrun error indicator */
 #define UART_LSR_DR		0x01 /* Receiver data ready */
 #define UART_LSR_BRK_ERROR_BITS	0x1E /* BI, FE, PE, OE bits */
+#define UART_LSR_RFE_ERROR_BITS	0xF1 /* RFE, TEMT, THRE, BI, DR bits */
 
 #define UART_MSR	6	/* In:  Modem Status Register */
 #define UART_MSR_DCD		0x80 /* Data Carrier Detect */