Re: [PATCH 1/1] tty, serial, 8250: to avoid recv fifo overrun, read rx fifo during xmit

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Pl take a look at this patch. This is second version based and tested
on 3.19-rc2.

George Spelvin,

I'd like to add your name to Signed-off-by as well.

thanks.

On Wed, Jan 14, 2015 at 10:22 PM, Prasad Koya <prasad.koya@xxxxxxxxx> wrote:
> Patch is tested and based on 3.19-rc2.
>
> On Wed, Jan 14, 2015 at 11:47 AM,  <prasad.koya@xxxxxxxxx> wrote:
>> From 859779819fe0490daaddeff5cb3cdda7a4372584 Mon Sep 17 00:00:00 2001
>> From: Prasad Koya <prasad@xxxxxxxxxx>
>> Date: Wed, 14 Jan 2015 11:07:41 -0800
>> Subject: [PATCH 1/1] tty, serial, 8250: to avoid recv fifo overrun, read rx fifo during xmit
>>
>> At slow baud rates, say 9600, it is easy to run into tty buffer overrun
>> as interrupts could get disabled for a long time. To avoid that, if
>> UART_LSR_DR is set, pick up bytes from rx fifo while waiting for tx
>> buffer to be empty. Stop buffering if port->sysrq is true or
>> oops_in_progress is set.
>>
>> George Spelvin reworked original patch quite a bit.
>>
>> Tested on 16550 UART with 16byte FIFO
>>
>> Signed-off-by: Prasad Koya <prasad@xxxxxxxxxx>
>> ---
>>  drivers/tty/serial/8250/8250_core.c | 65 +++++++++++++++++++++++++++++++++----
>>  drivers/tty/serial/8250/8250_fsl.c  |  2 +-
>>  include/linux/serial_8250.h         |  3 +-
>>  include/linux/serial_core.h         |  2 +-
>>  4 files changed, 63 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
>> index 11c6685..a9adf9d 100644
>> --- a/drivers/tty/serial/8250/8250_core.c
>> +++ b/drivers/tty/serial/8250/8250_core.c
>> @@ -1434,9 +1434,12 @@ static void serial8250_enable_ms(struct uart_port *port)
>>   * serial8250_rx_chars: processes according to the passed in LSR
>>   * value, and returns the remaining LSR bits not handled
>>   * by this Rx routine.
>> + * no_sysrq is normally false, but when set it indicates we should stop
>> + * processing input after receiving a break, rather than passing the
>> + * next character to uart_handle_sysrq_char.
>>   */
>>  unsigned char
>> -serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
>> +serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr, bool no_sysrq)
>>  {
>>         struct uart_port *port = &up->port;
>>         unsigned char ch;
>> @@ -1472,8 +1475,11 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
>>                                  * may get masked by ignore_status_mask
>>                                  * or read_status_mask.
>>                                  */
>> -                               if (uart_handle_break(port))
>> +                               if (uart_handle_break(port)) {
>> +                                       if (no_sysrq)
>> +                                               max_count = 0;
>>                                         goto ignore_char;
>> +                               }
>>                         } else if (lsr & UART_LSR_PE)
>>                                 port->icount.parity++;
>>                         else if (lsr & UART_LSR_FE)
>> @@ -1609,7 +1615,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, false);
>>         }
>>         serial8250_modem_status(up);
>>         if ((!up->dma || (up->dma && up->dma->tx_err)) &&
>> @@ -1962,9 +1968,30 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
>>  }
>>
>>  /*
>> + * In some special situations, we allow console output without necessarily
>> + * locking the port.  The same situations also suppress processing input
>> + * during polling output, because we aren't ready to deal with it.
>> + * So just hope the hardware FIFO can hold until interrupts are
>> + * re-enabled.
>> + */
>> +static bool emergency_situation(const struct uart_port *port)
>> +{
>> +#ifdef SUPPORT_SYSRQ
>> +       return port->sysrq != 0 || oops_in_progress;
>> +#else
>> +       (void)port;
>> +       return oops_in_progress;
>> +#endif
>> +}
>> +
>> +/*
>>   *     Wait for transmitter & holding register to empty
>> + *     If rx is true, then also poll for received characters if it's
>> + *     safe to process them.  This is only used in the SUPPORT_SYSRQ
>> + *     case, and hopefully the compiler can figure out it's dead code
>> + *     if that's not the case.
>>   */
>> -static void wait_for_xmitr(struct uart_8250_port *up, int bits)
>> +static void __wait_for_xmitr(struct uart_8250_port *up, int bits, bool rx)
>>  {
>>         unsigned int status, tmout = 10000;
>>
>> @@ -1978,6 +2005,11 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
>>                         break;
>>                 if (--tmout == 0)
>>                         break;
>> +
>> +               if (rx && status & (UART_LSR_DR | UART_LSR_BI) &&
>> +                   !emergency_situation(&up->port))
>> +                       serial8250_rx_chars(up, status, true);
>> +
>>                 udelay(1);
>>         }
>>
>> @@ -1989,12 +2021,29 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
>>                         up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
>>                         if (msr & UART_MSR_CTS)
>>                                 break;
>> +
>> +                       if (rx && !emergency_situation(&up->port)) {
>> +                               status = serial_in(up, UART_LSR);
>> +
>> +                               up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
>> +                               if (status & (UART_LSR_DR | UART_LSR_BI))
>> +                                       serial8250_rx_chars(up, status, true);
>> +                       }
>> +
>>                         udelay(1);
>>                         touch_nmi_watchdog();
>>                 }
>>         }
>>  }
>>
>> +/*
>> + *     Wait for transmitter & holding register to empty
>> + */
>> +static void wait_for_xmitr(struct uart_8250_port *up, int bits)
>> +{
>> +       __wait_for_xmitr(up, bits, false);
>> +}
>> +
>>  #ifdef CONFIG_CONSOLE_POLL
>>  /*
>>   * Console polling routines for writing and reading from the uart while
>> @@ -3168,7 +3217,7 @@ static void serial8250_console_putchar(struct uart_port *port, int ch)
>>  {
>>         struct uart_8250_port *up = up_to_u8250p(port);
>>
>> -       wait_for_xmitr(up, UART_LSR_THRE);
>> +       __wait_for_xmitr(up, UART_LSR_THRE, true);
>>         serial_port_out(port, UART_TX, ch);
>>  }
>>
>> @@ -3176,6 +3225,10 @@ static void serial8250_console_putchar(struct uart_port *port, int ch)
>>   *     Print a string to the serial port trying not to disturb
>>   *     any possible real use of the port...
>>   *
>> + *     In order to avoid dropped input if the output is longer than
>> + *     the available hardware FIFO space, we try to handle incoming
>> + *     characters during this polling loop.
>> + *
>>   *     The console_lock must be held when we get here.
>>   */
>>  static void
>> @@ -3214,7 +3267,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
>>          *      Finally, wait for transmitter to become empty
>>          *      and restore the IER
>>          */
>> -       wait_for_xmitr(up, BOTH_EMPTY);
>> +       __wait_for_xmitr(up, BOTH_EMPTY, true);
>>         serial_port_out(port, UART_IER, ier);
>>
>>         /*
>> diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
>> index c0533a5..25f0aa3 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, false);
>>
>>         serial8250_modem_status(up);
>>
>> diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
>> index e02acf0..8544bc5 100644
>> --- a/include/linux/serial_8250.h
>> +++ b/include/linux/serial_8250.h
>> @@ -128,7 +128,8 @@ extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
>>                              unsigned int oldstate);
>>  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,
>> +                                 bool no_sysrq);
>>  void serial8250_tx_chars(struct uart_8250_port *up);
>>  unsigned int serial8250_modem_status(struct uart_8250_port *up);
>>
>> diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
>> index 057038c..c93c5aa 100644
>> --- a/include/linux/serial_core.h
>> +++ b/include/linux/serial_core.h
>> @@ -410,7 +410,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
>>         if (port->sysrq) {
>>                 if (ch && time_before(jiffies, port->sysrq)) {
>>                         handle_sysrq(ch);
>> -                       port->sysrq = 0;
>> +                       port->sysrq = 0;   /* Must be AFTER handle_sysrq */
>>                         return 1;
>>                 }
>>                 port->sysrq = 0;
>> --
>> 1.8.1.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
--
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




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux