From patchwork Wed Apr 6 20:30:12 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Scott Wood X-Patchwork-Id: 90066 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 2CFBEB6F76 for ; Thu, 7 Apr 2011 06:30:33 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 7039D280B1; Wed, 6 Apr 2011 22:30:31 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OzWpl+yQBvyc; Wed, 6 Apr 2011 22:30:31 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8F597280A4; Wed, 6 Apr 2011 22:30:28 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D97F5280A4 for ; Wed, 6 Apr 2011 22:30:22 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3QbLa-upNtNf for ; Wed, 6 Apr 2011 22:30:21 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from ch1outboundpool.messaging.microsoft.com (ch1outboundpool.messaging.microsoft.com [216.32.181.185]) by theia.denx.de (Postfix) with ESMTPS id 06C38280A2 for ; Wed, 6 Apr 2011 22:30:19 +0200 (CEST) Received: from mail90-ch1-R.bigfish.com (216.32.181.170) by CH1EHSOBE008.bigfish.com (10.43.70.58) with Microsoft SMTP Server id 14.1.225.8; Wed, 6 Apr 2011 20:30:18 +0000 Received: from mail90-ch1 (localhost.localdomain [127.0.0.1]) by mail90-ch1-R.bigfish.com (Postfix) with ESMTP id 144581984D6 for ; Wed, 6 Apr 2011 20:30:18 +0000 (UTC) X-SpamScore: -3 X-BigFish: VS-3(zzbb2cKzz1202hzz8275bhz2dh2a8h637h668h839h61h) X-Spam-TCS-SCL: 0:0 X-Forefront-Antispam-Report: KIP:(null); UIP:(null); IPVD:NLI; H:mail.freescale.net; RD:none; EFVD:NLI Received: from mail90-ch1 (localhost.localdomain [127.0.0.1]) by mail90-ch1 (MessageSwitch) id 1302121817652638_2098; Wed, 6 Apr 2011 20:30:17 +0000 (UTC) Received: from CH1EHSMHS029.bigfish.com (snatpool1.int.messaging.microsoft.com [10.43.68.242]) by mail90-ch1.bigfish.com (Postfix) with ESMTP id 91AE23E0050 for ; Wed, 6 Apr 2011 20:30:17 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by CH1EHSMHS029.bigfish.com (10.43.70.29) with Microsoft SMTP Server (TLS) id 14.1.225.8; Wed, 6 Apr 2011 20:30:14 +0000 Received: from az33smr01.freescale.net (10.64.34.199) by 039-SN1MMR1-003.039d.mgd.msft.net (10.84.1.16) with Microsoft SMTP Server id 14.1.270.2; Wed, 6 Apr 2011 15:30:13 -0500 Received: from schlenkerla.am.freescale.net (schlenkerla.am.freescale.net [10.82.120.180]) by az33smr01.freescale.net (8.13.1/8.13.0) with ESMTP id p36KUCED025735; Wed, 6 Apr 2011 15:30:13 -0500 (CDT) Date: Wed, 6 Apr 2011 15:30:12 -0500 From: Scott Wood To: Message-ID: <20110406203012.GA30167@schlenkerla.am.freescale.net> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) X-OriginatorOrg: freescale.com Subject: [U-Boot] [PATCH 1/2] NS16550: buffer reads X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This improves the performance of U-Boot when accepting rapid input, such as pasting a sequence of commands. Without this patch, on P4080DS I see a maximum of around 5 mw.l lines can be pasted. With this patch, it handles around 70 lines before lossage, long enough for most things you'd paste. Signed-off-by: Scott Wood --- README | 8 ++++ drivers/serial/ns16550.c | 96 +++++++++++++++++++++++++++++++++++++++++++-- drivers/serial/serial.c | 4 +- include/ns16550.h | 4 +- 4 files changed, 103 insertions(+), 9 deletions(-) diff --git a/README b/README index bd03523..d21ea9c 100644 --- a/README +++ b/README @@ -2682,6 +2682,14 @@ use the "saveenv" command to store a valid environment. space for already greatly restricted images, including but not limited to NAND_SPL configurations. +- CONFIG_NS16550_BUFFER_READS: + Instead of reading directly from the receive register + every time U-Boot is ready for another byte, keep a + buffer and fill it from the hardware fifo every time + U-Boot reads a character. This helps U-Boot keep up with + a larger amount of rapid input, such as happens when + pasting text into the terminal. + Low Level (hardware related) configuration options: --------------------------------------------------- diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 8eeb48f..ed3428d 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -4,12 +4,15 @@ * modified to use CONFIG_SYS_ISA_MEM and new defines */ +#include #include #include #include #include #include +DECLARE_GLOBAL_DATA_PTR; + #define UART_LCRVAL UART_LCR_8N1 /* 8 data, 1 stop, no parity */ #define UART_MCRVAL (UART_MCR_DTR | \ UART_MCR_RTS) /* RTS/DTR */ @@ -86,21 +89,104 @@ void NS16550_putc (NS16550_t com_port, char c) } #ifndef CONFIG_NS16550_MIN_FUNCTIONS -char NS16550_getc (NS16550_t com_port) + +static char NS16550_raw_getc(NS16550_t regs) { - while ((serial_in(&com_port->lsr) & UART_LSR_DR) == 0) { + while ((serial_in(®s->lsr) & UART_LSR_DR) == 0) { #ifdef CONFIG_USB_TTY extern void usbtty_poll(void); usbtty_poll(); #endif WATCHDOG_RESET(); } - return serial_in(&com_port->rbr); + return serial_in(®s->rbr); +} + +static int NS16550_raw_tstc(NS16550_t regs) +{ + return ((serial_in(®s->lsr) & UART_LSR_DR) != 0); +} + + +#ifdef CONFIG_NS16550_BUFFER_READS + +#define BUF_SIZE 256 +#define NUM_PORTS 4 + +struct ns16550_priv { + char buf[BUF_SIZE]; + unsigned int head, tail; +}; + +static struct ns16550_priv rxstate[NUM_PORTS]; + +static void enqueue(unsigned int port, char ch) +{ + /* If queue is full, drop the character. */ + if ((rxstate[port].head - rxstate[port].tail - 1) % BUF_SIZE == 0) + return; + + rxstate[port].buf[rxstate[port].tail] = ch; + rxstate[port].tail = (rxstate[port].tail + 1) % BUF_SIZE; +} + +static int dequeue(unsigned int port, char *ch) +{ + /* Empty queue? */ + if (rxstate[port].head == rxstate[port].tail) + return 0; + + *ch = rxstate[port].buf[rxstate[port].head]; + rxstate[port].head = (rxstate[port].head + 1) % BUF_SIZE; + return 1; +} + +static void fill_rx_buf(NS16550_t regs, unsigned int port) +{ + while ((serial_in(®s->lsr) & UART_LSR_DR) != 0) + enqueue(port, serial_in(®s->rbr)); +} + +char NS16550_getc(NS16550_t regs, unsigned int port) +{ + char ch; + + if (port >= NUM_PORTS || !(gd->flags & GD_FLG_RELOC)) + return NS16550_raw_getc(regs); + + do { +#ifdef CONFIG_USB_TTY + extern void usbtty_poll(void); + usbtty_poll(); +#endif + fill_rx_buf(regs, port); + WATCHDOG_RESET(); + } while (!dequeue(port, &ch)); + + return ch; +} + +int NS16550_tstc(NS16550_t regs, unsigned int port) +{ + if (port >= NUM_PORTS || !(gd->flags & GD_FLG_RELOC)) + return NS16550_raw_tstc(regs); + + fill_rx_buf(regs, port); + + return rxstate[port].head != rxstate[port].tail; +} + +#else /* CONFIG_NS16550_BUFFER_READS */ + +char NS16550_getc(NS16550_t regs, unsigned int port) +{ + return NS16550_raw_getc(regs); } -int NS16550_tstc (NS16550_t com_port) +int NS16550_tstc(NS16550_t regs, unsigned int port) { - return ((serial_in(&com_port->lsr) & UART_LSR_DR) != 0); + return NS16550_raw_tstc(regs); } +#endif /* CONFIG_NS16550_BUFFER_READS */ #endif /* CONFIG_NS16550_MIN_FUNCTIONS */ diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 4032dfd..3fc80b1 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -219,13 +219,13 @@ _serial_puts (const char *s,const int port) int _serial_getc(const int port) { - return NS16550_getc(PORT); + return NS16550_getc(PORT, port); } int _serial_tstc(const int port) { - return NS16550_tstc(PORT); + return NS16550_tstc(PORT, port); } void diff --git a/include/ns16550.h b/include/ns16550.h index 9ea81e9..fa3e62e 100644 --- a/include/ns16550.h +++ b/include/ns16550.h @@ -160,6 +160,6 @@ typedef volatile struct NS16550 *NS16550_t; void NS16550_init (NS16550_t com_port, int baud_divisor); void NS16550_putc (NS16550_t com_port, char c); -char NS16550_getc (NS16550_t com_port); -int NS16550_tstc (NS16550_t com_port); +char NS16550_getc (NS16550_t regs, unsigned int port); +int NS16550_tstc (NS16550_t regs, unsigned int port); void NS16550_reinit (NS16550_t com_port, int baud_divisor);