From patchwork Thu Feb 11 09:58:47 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Murphy X-Patchwork-Id: 78673 Received: from devils.ext.ti.com (devils.ext.ti.com [198.47.26.153]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o1BA47o0024376 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 11 Feb 2010 10:04:51 GMT Received: from dlep33.itg.ti.com ([157.170.170.112]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id o1B9wtaB017143 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 11 Feb 2010 03:58:55 -0600 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep33.itg.ti.com (8.13.7/8.13.7) with ESMTP id o1B9wrKb027678; Thu, 11 Feb 2010 03:58:54 -0600 (CST) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 75FAD80627; Thu, 11 Feb 2010 03:58:53 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp53.itg.ti.com (dflp53.itg.ti.com [128.247.5.6]) by linux.omap.com (Postfix) with ESMTP id A131380626 for ; Thu, 11 Feb 2010 03:58:51 -0600 (CST) Received: from white.ext.ti.com (localhost [127.0.0.1]) by dflp53.itg.ti.com (8.13.8/8.13.8) with ESMTP id o1B9wpKf025679 for ; Thu, 11 Feb 2010 03:58:51 -0600 (CST) Received: from psmtp.com (na3sys009amx235.postini.com [74.125.149.119]) by white.ext.ti.com (8.13.7/8.13.7) with SMTP id o1B9wnqO029360 for ; Thu, 11 Feb 2010 03:58:50 -0600 Received: from source ([209.85.219.216]) by na3sys009amx235.postini.com ([74.125.148.10]) with SMTP; Thu, 11 Feb 2010 09:58:50 GMT Received: by ewy8 with SMTP id 8so1138430ewy.29 for ; Thu, 11 Feb 2010 01:58:48 -0800 (PST) MIME-Version: 1.0 Received: by 10.216.93.1 with SMTP id k1mr849813wef.151.1265882327720; Thu, 11 Feb 2010 01:58:47 -0800 (PST) Date: Thu, 11 Feb 2010 10:58:47 +0100 Message-ID: Subject: RE: DM3xx: UART transmit delays From: Brian Murphy To: davinci-linux-open-source@linux.davincidsp.com X-pstn-neptune: 0/0/0.00/0 X-pstn-levels: (S:99.90000/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:88.1613 C:98.6951 ) X-pstn-settings: 2 (0.5000:0.5000) s cv gt3 gt2 gt1 r p m X-pstn-addresses: from [db-null] X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Thu, 11 Feb 2010 10:04:52 +0000 (UTC) From 73b3fdf65baef4d532787677dc709b6390b24d8a Mon Sep 17 00:00:00 2001 From: Brian Murphy Date: Fri, 5 Feb 2010 15:59:02 +0100 Subject: [PATCH] performance fix --- drivers/serial/8250.c | 204 +++++++++---------------------------------------- drivers/serial/8250.h | 4 +- 2 files changed, 38 insertions(+), 170 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index c3e37c8..646e8ce 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -150,6 +150,7 @@ struct uart_8250_port { unsigned char lsr_saved_flags; #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA unsigned char msr_saved_flags; + unsigned char tx_active; /* * We provide a per-port pm hook. @@ -524,25 +525,6 @@ static void set_io_from_upio(struct uart_port *p) up->cur_iotype = p->iotype; } -static void -serial_out_sync(struct uart_8250_port *up, int offset, int value) -{ - struct uart_port *p = &up->port; - switch (p->iotype) { - case UPIO_MEM: - case UPIO_MEM32: -#ifdef CONFIG_SERIAL_8250_AU1X00 - case UPIO_AU: -#endif - case UPIO_DWAPB: - p->serial_out(p, offset, value); - p->serial_in(p, UART_LCR); /* safe, no side-effects */ - break; - default: - p->serial_out(p, offset, value); - } -} - #define serial_in(up, offset) \ (up->port.serial_in(&(up)->port, (offset))) #define serial_out(up, offset, value) \ @@ -1311,14 +1293,20 @@ static inline void __stop_tx(struct uart_8250_port *p) p->ier &= ~UART_IER_THRI; serial_out(p, UART_IER, p->ier); } + p->tx_active = 0; } static void serial8250_stop_tx(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); __stop_tx(up); + spin_unlock_irqrestore(&up->port.lock, flags); + /* * We really want to stop the transmitter from sending. */ @@ -1333,22 +1321,23 @@ static void transmit_chars(struct uart_8250_port *up); static void serial8250_start_tx(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; serial_out(up, UART_IER, up->ier); + } - if (up->bugs & UART_BUG_TXEN) { - unsigned char lsr; - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if ((up->port.type == PORT_RM9000) ? - (lsr & UART_LSR_THRE) : - (lsr & UART_LSR_TEMT)) - transmit_chars(up); - } + if (!up->tx_active) + { + up->tx_active = 1; + transmit_chars(up); } + spin_unlock_irqrestore(&up->port.lock, flags); + /* * Re-enable the transmitter if we disabled it. */ @@ -1470,7 +1459,8 @@ static void transmit_chars(struct uart_8250_port *up) serial8250_stop_tx(&up->port); return; } - if (uart_circ_empty(xmit)) { + if (uart_circ_empty(xmit)) + { __stop_tx(up); return; } @@ -1488,9 +1478,6 @@ static void transmit_chars(struct uart_8250_port *up) uart_write_wakeup(&up->port); DEBUG_INTR("THRE..."); - - if (uart_circ_empty(xmit)) - __stop_tx(up); } static unsigned int check_modem_status(struct uart_8250_port *up) @@ -1519,12 +1506,9 @@ static unsigned int check_modem_status(struct uart_8250_port *up) /* * This handles the interrupt from one port. */ -static void serial8250_handle_port(struct uart_8250_port *up) +static void __serial8250_handle_port(struct uart_8250_port *up) { unsigned int status; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); status = serial_inp(up, UART_LSR); @@ -1534,8 +1518,19 @@ static void serial8250_handle_port(struct uart_8250_port *up) receive_chars(up, &status); check_modem_status(up); if (status & UART_LSR_THRE) + { + up->tx_active = 1; transmit_chars(up); + } + +} +static void serial8250_handle_port(struct uart_8250_port *up) +{ + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + __serial8250_handle_port(up); spin_unlock_irqrestore(&up->port.lock, flags); } @@ -1572,7 +1567,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) iir = serial_in(up, UART_IIR); if (!(iir & UART_IIR_NO_INT)) { - serial8250_handle_port(up); + __serial8250_handle_port(up); handled = 1; @@ -1644,6 +1639,8 @@ static int serial_link_irq_chain(struct uart_8250_port *up) struct irq_info *i; int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; + printk(KERN_INFO "serial_link_irq_chain\n"); + mutex_lock(&hash_mutex); h = &irq_lists[up->port.irq % NR_IRQ_HASH]; @@ -1678,6 +1675,7 @@ static int serial_link_irq_chain(struct uart_8250_port *up) i->head = &up->list; spin_unlock_irq(&i->lock); irq_flags |= up->port.irqflags; + printk(KERN_INFO "ttyS%d: request irq %d\n", serial_index(&up->port), up->port.irq); ret = request_irq(up->port.irq, serial8250_interrupt, irq_flags, "serial", i); if (ret < 0) @@ -1736,51 +1734,6 @@ static void serial8250_timeout(unsigned long data) mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout)); } -static void serial8250_backup_timeout(unsigned long data) -{ - struct uart_8250_port *up = (struct uart_8250_port *)data; - unsigned int iir, ier = 0, lsr; - unsigned long flags; - - /* - * Must disable interrupts or else we risk racing with the interrupt - * based handler. - */ - if (is_real_interrupt(up->port.irq)) { - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - } - - iir = serial_in(up, UART_IIR); - - /* - * This should be a safe test for anyone who doesn't trust the - * IIR bits on their UART, but it's specifically designed for - * the "Diva" UART used on the management processor on many HP - * ia64 and parisc boxes. - */ - spin_lock_irqsave(&up->port.lock, flags); - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - spin_unlock_irqrestore(&up->port.lock, flags); - if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && - (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && - (lsr & UART_LSR_THRE)) { - iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); - iir |= UART_IIR_THRI; - } - - if (!(iir & UART_IIR_NO_INT)) - serial8250_handle_port(up); - - if (is_real_interrupt(up->port.irq)) - serial_out(up, UART_IER, ier); - - /* Standard timer interval plus 0.2s to keep the port running */ - mod_timer(&up->timer, - jiffies + poll_timeout(up->port.timeout) + HZ / 5); -} - static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; @@ -1942,9 +1895,9 @@ static int serial8250_startup(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned long flags; - unsigned char lsr, iir; int retval; + up->tx_active = 0; up->capabilities = uart_config[up->port.type].flags; up->mcr = 0; @@ -2015,62 +1968,13 @@ static int serial8250_startup(struct uart_port *port) serial_outp(up, UART_LCR, 0); } - if (is_real_interrupt(up->port.irq)) { - unsigned char iir1; - /* - * Test for UARTs that do not reassert THRE when the - * transmitter is idle and the interrupt has already - * been cleared. Real 16550s should always reassert - * this interrupt whenever the transmitter is idle and - * the interrupt is enabled. Delays are necessary to - * allow register changes to become visible. - */ - spin_lock_irqsave(&up->port.lock, flags); - if (up->port.irqflags & IRQF_SHARED) - disable_irq_nosync(up->port.irq); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_out_sync(up, UART_IER, UART_IER_THRI); - udelay(1); /* allow THRE to set */ - iir1 = serial_in(up, UART_IIR); - serial_out(up, UART_IER, 0); - serial_out_sync(up, UART_IER, UART_IER_THRI); - udelay(1); /* allow a working UART time to re-assert THRE */ - iir = serial_in(up, UART_IIR); - serial_out(up, UART_IER, 0); - - if (up->port.irqflags & IRQF_SHARED) - enable_irq(up->port.irq); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * If the interrupt is not reasserted, setup a timer to - * kick the UART on a regular basis. - */ - if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { - up->bugs |= UART_BUG_THRE; - pr_debug("ttyS%d - using backup timer\n", - serial_index(port)); - } - } - - /* - * The above check will only give an accurate result the first time - * the port is opened so this value needs to be preserved. - */ - if (up->bugs & UART_BUG_THRE) { - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - poll_timeout(up->port.timeout) + HZ / 5); - } - /* * If the "interrupt" for this port doesn't correspond with any * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. */ if (!is_real_interrupt(up->port.irq)) { + printk("not real interrupt %d\n", up->port.irq); up->timer.data = (unsigned long)up; mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout)); } else { @@ -2097,40 +2001,6 @@ static int serial8250_startup(struct uart_port *port) serial8250_set_mctrl(&up->port, up->port.mctrl); - /* Serial over Lan (SoL) hack: - Intel 8257x Gigabit ethernet chips have a - 16550 emulation, to be used for Serial Over Lan. - Those chips take a longer time than a normal - serial device to signalize that a transmission - data was queued. Due to that, the above test generally - fails. One solution would be to delay the reading of - iir. However, this is not reliable, since the timeout - is variable. So, let's just don't test if we receive - TX irq. This way, we'll never enable UART_BUG_TXEN. - */ - if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST) - goto dont_test_tx_en; - - /* - * Do a quick test to see if we receive an - * interrupt when we enable the TX irq. - */ - serial_outp(up, UART_IER, UART_IER_THRI); - lsr = serial_in(up, UART_LSR); - iir = serial_in(up, UART_IIR); - serial_outp(up, UART_IER, 0); - - if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { - if (!(up->bugs & UART_BUG_TXEN)) { - up->bugs |= UART_BUG_TXEN; - pr_debug("ttyS%d - enabling bad tx status workarounds\n", - serial_index(port)); - } - } else { - up->bugs &= ~UART_BUG_TXEN; - } - -dont_test_tx_en: spin_unlock_irqrestore(&up->port.lock, flags); /* diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h index 6e19ea3..770a0e2 100644 --- a/drivers/serial/8250.h +++ b/drivers/serial/8250.h @@ -46,9 +46,7 @@ struct serial8250_config { #define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */ #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ -#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_NOMSR (1 << 1) /* UART has buggy MSR status bits (Au1x00) */ #define PROBE_RSA (1 << 0) #define PROBE_ANY (~0) -- 1.6.5.3