drm: wbinvd is cache coherent.
[safe/jmp/linux-2.6] / drivers / serial / 8250.c
index 96a585e..1528de2 100644 (file)
@@ -12,8 +12,6 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- *  $Id: 8250.c,v 1.90 2002/07/28 10:03:27 rmk Exp $
- *
  * A note about mapbase / membase
  *
  *  mapbase is the physical address of the IO port.
 
 #include "8250.h"
 
+#ifdef CONFIG_SPARC
+#include "suncore.h"
+#endif
+
 /*
  * Configuration:
  *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
@@ -55,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 
 static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
 
+static struct uart_driver serial8250_reg;
+
+static int serial_index(struct uart_port *port)
+{
+       return (serial8250_reg.minor - 64) + port->line;
+}
+
 /*
  * Debugging.
  */
@@ -93,7 +102,6 @@ static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
 #define CONFIG_HUB6 1
 
 #include <asm/serial.h>
-
 /*
  * SERIAL_PORT_DFNS tells us about built-in ports that have no
  * standard enumeration mechanism.   Platforms that can find all
@@ -539,7 +547,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
 /*
  * FIFO support.
  */
-static inline void serial8250_clear_fifos(struct uart_8250_port *p)
+static void serial8250_clear_fifos(struct uart_8250_port *p)
 {
        if (p->capabilities & UART_CAP_FIFO) {
                serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -554,7 +562,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p)
  * capability" bit enabled.  Note that on XR16C850s, we need to
  * reset LCR to write to IER.
  */
-static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
 {
        if (p->capabilities & UART_CAP_SLEEP) {
                if (p->capabilities & UART_CAP_EFR) {
@@ -996,7 +1004,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
                return;
 
        DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
-                       up->port.line, up->port.iobase, up->port.membase);
+                      serial_index(&up->port), up->port.iobase, up->port.membase);
 
        /*
         * We really do need global IRQs disabled here - we're going to
@@ -1131,8 +1139,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        if (up->capabilities != uart_config[up->port.type].flags) {
                printk(KERN_WARNING
                       "ttyS%d: detected caps %08x should be %08x\n",
-                       up->port.line, up->capabilities,
-                       uart_config[up->port.type].flags);
+                      serial_index(&up->port), up->capabilities,
+                      uart_config[up->port.type].flags);
        }
 
        up->port.fifosize = uart_config[up->port.type].fifo_size;
@@ -1290,13 +1298,24 @@ static void serial8250_enable_ms(struct uart_port *port)
 static void
 receive_chars(struct uart_8250_port *up, unsigned int *status)
 {
-       struct tty_struct *tty = up->port.info->tty;
+       struct tty_struct *tty = up->port.info->port.tty;
        unsigned char ch, lsr = *status;
        int max_count = 256;
        char flag;
 
        do {
-               ch = serial_inp(up, UART_RX);
+               if (likely(lsr & UART_LSR_DR))
+                       ch = serial_inp(up, UART_RX);
+               else
+                       /*
+                        * Intel 82571 has a Serial Over Lan device that will
+                        * set UART_LSR_BI without setting UART_LSR_DR when
+                        * it receives a break. To avoid reading from the
+                        * receive buffer without UART_LSR_DR bit set, we
+                        * just force the read character to be 0
+                        */
+                       ch = 0;
+
                flag = TTY_NORMAL;
                up->port.icount.rx++;
 
@@ -1345,7 +1364,7 @@ receive_chars(struct uart_8250_port *up, unsigned int *status)
 
 ignore_char:
                lsr = serial_inp(up, UART_LSR);
-       } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
+       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
        spin_unlock(&up->port.lock);
        tty_flip_buffer_push(tty);
        spin_lock(&up->port.lock);
@@ -1416,8 +1435,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
 /*
  * This handles the interrupt from one port.
  */
-static inline 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;
@@ -1428,7 +1446,7 @@ serial8250_handle_port(struct uart_8250_port *up)
 
        DEBUG_INTR("status = %x...", status);
 
-       if (status & UART_LSR_DR)
+       if (status & (UART_LSR_DR | UART_LSR_BI))
                receive_chars(up, &status);
        check_modem_status(up);
        if (status & UART_LSR_THRE)
@@ -1711,7 +1729,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
 /*
  *     Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
        unsigned int status, tmout = 10000;
 
@@ -1846,7 +1864,8 @@ static int serial8250_startup(struct uart_port *port)
         */
        if (!(up->port.flags & UPF_BUGGY_UART) &&
            (serial_inp(up, UART_LSR) == 0xff)) {
-               printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+                      serial_index(&up->port));
                return -ENODEV;
        }
 
@@ -1868,6 +1887,7 @@ static int serial8250_startup(struct uart_port *port)
        }
 
        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
@@ -1877,33 +1897,46 @@ static int serial8250_startup(struct uart_port *port)
                 * allow register changes to become visible.
                 */
                spin_lock_irqsave(&up->port.lock, flags);
+               if (up->port.flags & UPF_SHARE_IRQ)
+                       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 */
-               serial_in(up, UART_IIR);
+               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.flags & UPF_SHARE_IRQ)
+                       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 (iir & UART_IIR_NO_INT) {
-                       pr_debug("ttyS%d - using backup timer\n", port->line);
-                       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 (!(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.
@@ -1948,7 +1981,7 @@ static int serial8250_startup(struct uart_port *port)
                if (!(up->bugs & UART_BUG_TXEN)) {
                        up->bugs |= UART_BUG_TXEN;
                        pr_debug("ttyS%d - enabling bad tx status workarounds\n",
-                                port->line);
+                                serial_index(port));
                }
        } else {
                up->bugs &= ~UART_BUG_TXEN;
@@ -2190,9 +2223,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
                serial_outp(up, UART_EFR, efr);
        }
 
-#ifdef CONFIG_ARCH_OMAP15XX
+#ifdef CONFIG_ARCH_OMAP
        /* Workaround to enable 115200 baud on OMAP1510 internal ports */
-       if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {
+       if (cpu_is_omap1510() && is_omap_port(up)) {
                if (baud == 115200) {
                        quot = 1;
                        serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
@@ -2228,7 +2261,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
        }
        serial8250_set_mctrl(&up->port, up->port.mctrl);
        spin_unlock_irqrestore(&up->port.lock, flags);
-       tty_termios_encode_baud_rate(termios, baud, baud);
+       /* Don't rewrite B0 */
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
 }
 
 static void
@@ -2243,18 +2278,27 @@ serial8250_pm(struct uart_port *port, unsigned int state,
                p->pm(port, state, oldstate);
 }
 
+static unsigned int serial8250_port_size(struct uart_8250_port *pt)
+{
+       if (pt->port.iotype == UPIO_AU)
+               return 0x100000;
+#ifdef CONFIG_ARCH_OMAP
+       if (is_omap_port(pt))
+               return 0x16 << pt->port.regshift;
+#endif
+       return 8 << pt->port.regshift;
+}
+
 /*
  * Resource handling.
  */
 static int serial8250_request_std_resource(struct uart_8250_port *up)
 {
-       unsigned int size = 8 << up->port.regshift;
+       unsigned int size = serial8250_port_size(up);
        int ret = 0;
 
        switch (up->port.iotype) {
        case UPIO_AU:
-               size = 0x100000;
-               /* fall thru */
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
@@ -2268,7 +2312,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
                }
 
                if (up->port.flags & UPF_IOREMAP) {
-                       up->port.membase = ioremap(up->port.mapbase, size);
+                       up->port.membase = ioremap_nocache(up->port.mapbase,
+                                                                       size);
                        if (!up->port.membase) {
                                release_mem_region(up->port.mapbase, size);
                                ret = -ENOMEM;
@@ -2287,12 +2332,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
 
 static void serial8250_release_std_resource(struct uart_8250_port *up)
 {
-       unsigned int size = 8 << up->port.regshift;
+       unsigned int size = serial8250_port_size(up);
 
        switch (up->port.iotype) {
        case UPIO_AU:
-               size = 0x100000;
-               /* fall thru */
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
@@ -2606,7 +2649,6 @@ static int serial8250_console_early_setup(void)
        return serial8250_find_port_for_earlycon();
 }
 
-static struct uart_driver serial8250_reg;
 static struct console serial8250_console = {
        .name           = "ttyS",
        .write          = serial8250_console_write,
@@ -2620,6 +2662,9 @@ static struct console serial8250_console = {
 
 static int __init serial8250_console_init(void)
 {
+       if (nr_uarts > UART_NR)
+               nr_uarts = UART_NR;
+
        serial8250_isa_init_ports();
        register_console(&serial8250_console);
        return 0;
@@ -2650,7 +2695,6 @@ static struct uart_driver serial8250_reg = {
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
        .minor                  = 64,
-       .nr                     = UART_NR,
        .cons                   = SERIAL8250_CONSOLE,
 };
 
@@ -2928,14 +2972,19 @@ static int __init serial8250_init(void)
        if (nr_uarts > UART_NR)
                nr_uarts = UART_NR;
 
-       printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ "
+       printk(KERN_INFO "Serial: 8250/16550 driver"
                "%d ports, IRQ sharing %sabled\n", nr_uarts,
                share_irqs ? "en" : "dis");
 
        for (i = 0; i < NR_IRQS; i++)
                spin_lock_init(&irq_lists[i].lock);
 
+#ifdef CONFIG_SPARC
+       ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+       serial8250_reg.nr = UART_NR;
        ret = uart_register_driver(&serial8250_reg);
+#endif
        if (ret)
                goto out;
 
@@ -2960,7 +3009,11 @@ static int __init serial8250_init(void)
  put_dev:
        platform_device_put(serial8250_isa_devs);
  unreg_uart_drv:
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
        uart_unregister_driver(&serial8250_reg);
+#endif
  out:
        return ret;
 }
@@ -2979,7 +3032,11 @@ static void __exit serial8250_exit(void)
        platform_driver_unregister(&serial8250_isa_driver);
        platform_device_unregister(isa_dev);
 
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
        uart_unregister_driver(&serial8250_reg);
+#endif
 }
 
 module_init(serial8250_init);
@@ -2989,7 +3046,7 @@ EXPORT_SYMBOL(serial8250_suspend_port);
 EXPORT_SYMBOL(serial8250_resume_port);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.90 $");
+MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
 
 module_param(share_irqs, uint, 0644);
 MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"