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

vb at vsbe.com vb at vsbe.com
Wed Mar 3 08:21:49 EST 2010


On Tue, Mar 2, 2010 at 8:27 AM, Paul Gortmaker
<paul.gortmaker at windriver.com> wrote:
> On 10-03-01 06:03 PM, vb at 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 at 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 at 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 at lists.ozlabs.org
>>> https://lists.ozlabs.org/listinfo/linuxppc-dev
>>>
>
>


More information about the Linuxppc-dev mailing list