Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / serial / 8250.c
index 30e8beb..fbb53ad 100644 (file)
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
-#include <linux/mca.h>
 #include <linux/delay.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial_reg.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
+#include <linux/nmi.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -53,6 +54,8 @@
  */
 static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 
+static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
+
 /*
  * Debugging.
  */
@@ -77,23 +80,9 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
  */
 #define is_real_interrupt(irq) ((irq) != 0)
 
-/*
- * This converts from our new CONFIG_ symbols to the symbols
- * that asm/serial.h expects.  You _NEED_ to comment out the
- * linux/config.h include contained inside asm/serial.h for
- * this to work.
- */
-#undef CONFIG_SERIAL_MANY_PORTS
-#undef CONFIG_SERIAL_DETECT_IRQ
-#undef CONFIG_SERIAL_MULTIPORT
-#undef CONFIG_HUB6
-
 #ifdef CONFIG_SERIAL_8250_DETECT_IRQ
 #define CONFIG_SERIAL_DETECT_IRQ 1
 #endif
-#ifdef CONFIG_SERIAL_8250_MULTIPORT
-#define CONFIG_SERIAL_MULTIPORT 1
-#endif
 #ifdef CONFIG_SERIAL_8250_MANY_PORTS
 #define CONFIG_SERIAL_MANY_PORTS 1
 #endif
@@ -115,11 +104,11 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 #define SERIAL_PORT_DFNS
 #endif
 
-static struct old_serial_port old_serial_port[] = {
+static const struct old_serial_port old_serial_port[] = {
        SERIAL_PORT_DFNS /* defined in asm/serial.h */
 };
 
-#define UART_NR        (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS)
+#define UART_NR        CONFIG_SERIAL_8250_NR_UARTS
 
 #ifdef CONFIG_SERIAL_8250_RSA
 
@@ -132,9 +121,9 @@ struct uart_8250_port {
        struct uart_port        port;
        struct timer_list       timer;          /* "no irq" timer */
        struct list_head        list;           /* ports on this IRQ */
-       unsigned int            capabilities;   /* port capabilities */
+       unsigned short          capabilities;   /* port capabilities */
+       unsigned short          bugs;           /* port bugs */
        unsigned int            tx_loadsz;      /* transmit fifo load size */
-       unsigned short          rev;
        unsigned char           acr;
        unsigned char           ier;
        unsigned char           lcr;
@@ -265,9 +254,53 @@ static const struct serial8250_config uart_config[] = {
        },
 };
 
-static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
+#ifdef CONFIG_SERIAL_8250_AU1X00
+
+/* Au1x00 UART hardware has a weird register layout */
+static const u8 au_io_in_map[] = {
+       [UART_RX]  = 0,
+       [UART_IER] = 2,
+       [UART_IIR] = 3,
+       [UART_LCR] = 5,
+       [UART_MCR] = 6,
+       [UART_LSR] = 7,
+       [UART_MSR] = 8,
+};
+
+static const u8 au_io_out_map[] = {
+       [UART_TX]  = 1,
+       [UART_IER] = 2,
+       [UART_FCR] = 4,
+       [UART_LCR] = 5,
+       [UART_MCR] = 6,
+};
+
+/* sane hardware needs no mapping */
+static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
 {
-       offset <<= up->port.regshift;
+       if (up->port.iotype != UPIO_AU)
+               return offset;
+       return au_io_in_map[offset];
+}
+
+static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+{
+       if (up->port.iotype != UPIO_AU)
+               return offset;
+       return au_io_out_map[offset];
+}
+
+#else
+
+/* sane hardware needs no mapping */
+#define map_8250_in_reg(up, offset) (offset)
+#define map_8250_out_reg(up, offset) (offset)
+
+#endif
+
+static unsigned int serial_in(struct uart_8250_port *up, int offset)
+{
+       offset = map_8250_in_reg(up, offset) << up->port.regshift;
 
        switch (up->port.iotype) {
        case UPIO_HUB6:
@@ -280,15 +313,20 @@ static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
        case UPIO_MEM32:
                return readl(up->port.membase + offset);
 
+#ifdef CONFIG_SERIAL_8250_AU1X00
+       case UPIO_AU:
+               return __raw_readl(up->port.membase + offset);
+#endif
+
        default:
                return inb(up->port.iobase + offset);
        }
 }
 
-static _INLINE_ void
+static void
 serial_out(struct uart_8250_port *up, int offset, int value)
 {
-       offset <<= up->port.regshift;
+       offset = map_8250_out_reg(up, offset) << up->port.regshift;
 
        switch (up->port.iotype) {
        case UPIO_HUB6:
@@ -304,6 +342,12 @@ serial_out(struct uart_8250_port *up, int offset, int value)
                writel(value, up->port.membase + offset);
                break;
 
+#ifdef CONFIG_SERIAL_8250_AU1X00
+       case UPIO_AU:
+               __raw_writel(value, up->port.membase + offset);
+               break;
+#endif
+
        default:
                outb(value, up->port.iobase + offset);
        }
@@ -318,6 +362,40 @@ serial_out(struct uart_8250_port *up, int offset, int value)
 #define serial_inp(up, offset)         serial_in(up, offset)
 #define serial_outp(up, offset, value) serial_out(up, offset, value)
 
+/* Uart divisor latch read */
+static inline int _serial_dl_read(struct uart_8250_port *up)
+{
+       return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static inline void _serial_dl_write(struct uart_8250_port *up, int value)
+{
+       serial_outp(up, UART_DLL, value & 0xff);
+       serial_outp(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+/* Au1x00 haven't got a standard divisor latch */
+static int serial_dl_read(struct uart_8250_port *up)
+{
+       if (up->port.iotype == UPIO_AU)
+               return __raw_readl(up->port.membase + 0x28);
+       else
+               return _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+       if (up->port.iotype == UPIO_AU)
+               __raw_writel(value, up->port.membase + 0x28);
+       else
+               _serial_dl_write(up, value);
+}
+#else
+#define serial_dl_read(up) _serial_dl_read(up)
+#define serial_dl_write(up, value) _serial_dl_write(up, value)
+#endif
 
 /*
  * For the 16C950
@@ -450,7 +528,8 @@ static void disable_rsa(struct uart_8250_port *up)
  */
 static int size_fifo(struct uart_8250_port *up)
 {
-       unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr;
+       unsigned char old_fcr, old_mcr, old_lcr;
+       unsigned short old_dl;
        int count;
 
        old_lcr = serial_inp(up, UART_LCR);
@@ -461,10 +540,8 @@ static int size_fifo(struct uart_8250_port *up)
                    UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
        serial_outp(up, UART_MCR, UART_MCR_LOOP);
        serial_outp(up, UART_LCR, UART_LCR_DLAB);
-       old_dll = serial_inp(up, UART_DLL);
-       old_dlm = serial_inp(up, UART_DLM);
-       serial_outp(up, UART_DLL, 0x01);
-       serial_outp(up, UART_DLM, 0x00);
+       old_dl = serial_dl_read(up);
+       serial_dl_write(up, 0x0001);
        serial_outp(up, UART_LCR, 0x03);
        for (count = 0; count < 256; count++)
                serial_outp(up, UART_TX, count);
@@ -475,8 +552,7 @@ static int size_fifo(struct uart_8250_port *up)
        serial_outp(up, UART_FCR, old_fcr);
        serial_outp(up, UART_MCR, old_mcr);
        serial_outp(up, UART_LCR, UART_LCR_DLAB);
-       serial_outp(up, UART_DLL, old_dll);
-       serial_outp(up, UART_DLM, old_dlm);
+       serial_dl_write(up, old_dl);
        serial_outp(up, UART_LCR, old_lcr);
 
        return count;
@@ -560,7 +636,14 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
        if (id1 == 0x16 && id2 == 0xC9 &&
            (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
                up->port.type = PORT_16C950;
-               up->rev = rev | (id3 << 8);
+
+               /*
+                * Enable work around for the Oxford Semiconductor 952 rev B
+                * chip which causes it to seriously miscalculate baud rates
+                * when DLL is 0.
+                */
+               if (id3 == 0x52 && rev == 0x01)
+                       up->bugs |= UART_BUG_QUOT;
                return;
        }
        
@@ -577,8 +660,6 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
 
        id2 = id1 >> 8;
        if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) {
-               if (id2 == 0x10)
-                       up->rev = id1 & 255;
                up->port.type = PORT_16850;
                return;
        }
@@ -701,8 +782,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 
                        serial_outp(up, UART_LCR, 0xE0);
 
-                       quot = serial_inp(up, UART_DLM) << 8;
-                       quot += serial_inp(up, UART_DLL);
+                       quot = serial_dl_read(up);
                        quot <<= 3;
 
                        status1 = serial_in(up, 0x04); /* EXCR1 */
@@ -710,8 +790,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
                        status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
                        serial_outp(up, 0x04, status1);
                        
-                       serial_outp(up, UART_DLL, quot & 0xff);
-                       serial_outp(up, UART_DLM, quot >> 8);
+                       serial_dl_write(up, quot);
 
                        serial_outp(up, UART_LCR, 0);
 
@@ -809,6 +888,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
 //     save_flags(flags); cli();
 
        up->capabilities = 0;
+       up->bugs = 0;
 
        if (!(up->port.flags & UPF_BUGGY_UART)) {
                /*
@@ -872,7 +952,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        /*
         * We're pretty sure there's a port here.  Lets find out what
         * type of port it is.  The IIR top two bits allows us to find
-        * out if its 8250 or 16450, 16550, 16550A or later.  This
+        * out if it's 8250 or 16450, 16550, 16550A or later.  This
         * determines what we test for next.
         *
         * We also initialise the EFR (if any) to zero for later.  The
@@ -918,6 +998,13 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
                }
        }
 #endif
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+       /* if access method is AU, it is a 16550 with a quirk */
+       if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
+               up->bugs |= UART_BUG_NOMSR;
+#endif
+
        serial_outp(up, UART_LCR, save_lcr);
 
        if (up->capabilities != uart_config[up->port.type].flags) {
@@ -944,7 +1031,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        serial_outp(up, UART_MCR, save_mcr);
        serial8250_clear_fifos(up);
        (void)serial_in(up, UART_RX);
-       serial_outp(up, UART_IER, 0);
+       if (up->capabilities & UART_CAP_UUE)
+               serial_outp(up, UART_IER, UART_IER_UUE);
+       else
+               serial_outp(up, UART_IER, 0);
 
  out:  
        spin_unlock_irqrestore(&up->port.lock, flags);
@@ -1001,38 +1091,52 @@ static void autoconfig_irq(struct uart_8250_port *up)
        up->port.irq = (irq > 0) ? irq : 0;
 }
 
-static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+       if (p->ier & UART_IER_THRI) {
+               p->ier &= ~UART_IER_THRI;
+               serial_out(p, UART_IER, p->ier);
+       }
+}
+
+static void serial8250_stop_tx(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
 
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
+       __stop_tx(up);
 
        /*
-        * We only do this from uart_stop - if we run out of
-        * characters to send, we don't want to prevent the
-        * FIFO from emptying.
+        * We really want to stop the transmitter from sending.
         */
-       if (up->port.type == PORT_16C950 && tty_stop) {
+       if (up->port.type == PORT_16C950) {
                up->acr |= UART_ACR_TXDIS;
                serial_icr_write(up, UART_ACR, up->acr);
        }
 }
 
-static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
+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;
 
        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, iir;
+                       lsr = serial_in(up, UART_LSR);
+                       iir = serial_in(up, UART_IIR);
+                       if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT)
+                               transmit_chars(up);
+               }
        }
+
        /*
-        * We only do this from uart_start
+        * Re-enable the transmitter if we disabled it.
         */
-       if (tty_start && up->port.type == PORT_16C950) {
+       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
                up->acr &= ~UART_ACR_TXDIS;
                serial_icr_write(up, UART_ACR, up->acr);
        }
@@ -1051,11 +1155,15 @@ static void serial8250_enable_ms(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
 
+       /* no MSR capabilities */
+       if (up->bugs & UART_BUG_NOMSR)
+               return;
+
        up->ier |= UART_IER_MSI;
        serial_out(up, UART_IER, up->ier);
 }
 
-static _INLINE_ void
+static void
 receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
 {
        struct tty_struct *tty = up->port.info->tty;
@@ -1064,19 +1172,6 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
        char flag;
 
        do {
-               /* The following is not allowed by the tty layer and
-                  unsafe. It should be fixed ASAP */
-               if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
-                       if (tty->low_latency) {
-                               spin_unlock(&up->port.lock);
-                               tty_flip_buffer_push(tty);
-                               spin_lock(&up->port.lock);
-                       }
-                       /*
-                        * If this failed then we will throw away the
-                        * bytes but must do so to clear interrupts
-                        */
-               }
                ch = serial_inp(up, UART_RX);
                flag = TTY_NORMAL;
                up->port.icount.rx++;
@@ -1141,7 +1236,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
        *status = lsr;
 }
 
-static _INLINE_ void transmit_chars(struct uart_8250_port *up)
+static void transmit_chars(struct uart_8250_port *up)
 {
        struct circ_buf *xmit = &up->port.info->xmit;
        int count;
@@ -1152,8 +1247,12 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
                up->port.x_char = 0;
                return;
        }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial8250_stop_tx(&up->port, 0);
+       if (uart_tx_stopped(&up->port)) {
+               serial8250_stop_tx(&up->port);
+               return;
+       }
+       if (uart_circ_empty(xmit)) {
+               __stop_tx(up);
                return;
        }
 
@@ -1172,28 +1271,27 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
        DEBUG_INTR("THRE...");
 
        if (uart_circ_empty(xmit))
-               serial8250_stop_tx(&up->port, 0);
+               __stop_tx(up);
 }
 
-static _INLINE_ void check_modem_status(struct uart_8250_port *up)
+static unsigned int check_modem_status(struct uart_8250_port *up)
 {
-       int status;
+       unsigned int status = serial_in(up, UART_MSR);
 
-       status = serial_in(up, UART_MSR);
-
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return;
+       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) {
+               if (status & UART_MSR_TERI)
+                       up->port.icount.rng++;
+               if (status & UART_MSR_DDSR)
+                       up->port.icount.dsr++;
+               if (status & UART_MSR_DDCD)
+                       uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+               if (status & UART_MSR_DCTS)
+                       uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
 
-       if (status & UART_MSR_TERI)
-               up->port.icount.rng++;
-       if (status & UART_MSR_DDSR)
-               up->port.icount.dsr++;
-       if (status & UART_MSR_DDCD)
-               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-       if (status & UART_MSR_DCTS)
-               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+               wake_up_interruptible(&up->port.info->delta_msr_wait);
+       }
 
-       wake_up_interruptible(&up->port.info->delta_msr_wait);
+       return status;
 }
 
 /*
@@ -1202,7 +1300,11 @@ static _INLINE_ void check_modem_status(struct uart_8250_port *up)
 static inline void
 serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
 {
-       unsigned int status = serial_inp(up, UART_LSR);
+       unsigned int status;
+
+       spin_lock(&up->port.lock);
+
+       status = serial_inp(up, UART_LSR);
 
        DEBUG_INTR("status = %x...", status);
 
@@ -1211,6 +1313,8 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
        check_modem_status(up);
        if (status & UART_LSR_THRE)
                transmit_chars(up);
+
+       spin_unlock(&up->port.lock);
 }
 
 /*
@@ -1246,9 +1350,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r
 
                iir = serial_in(up, UART_IIR);
                if (!(iir & UART_IIR_NO_INT)) {
-                       spin_lock(&up->port.lock);
                        serial8250_handle_port(up, regs);
-                       spin_unlock(&up->port.lock);
 
                        handled = 1;
 
@@ -1347,11 +1449,8 @@ static void serial8250_timeout(unsigned long data)
        unsigned int iir;
 
        iir = serial_in(up, UART_IIR);
-       if (!(iir & UART_IIR_NO_INT)) {
-               spin_lock(&up->port.lock);
+       if (!(iir & UART_IIR_NO_INT))
                serial8250_handle_port(up, NULL);
-               spin_unlock(&up->port.lock);
-       }
 
        timeout = up->port.timeout;
        timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
@@ -1374,13 +1473,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
 static unsigned int serial8250_get_mctrl(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
-       unsigned long flags;
-       unsigned char status;
+       unsigned int status;
        unsigned int ret;
 
-       spin_lock_irqsave(&up->port.lock, flags);
-       status = serial_in(up, UART_MSR);
-       spin_unlock_irqrestore(&up->port.lock, flags);
+       status = check_modem_status(up);
 
        ret = 0;
        if (status & UART_MSR_DCD)
@@ -1433,6 +1529,7 @@ 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->capabilities = uart_config[up->port.type].flags;
@@ -1461,7 +1558,7 @@ static int serial8250_startup(struct uart_port *port)
 
        /*
         * Clear the FIFO buffers and disable them.
-        * (they will be reeanbled in set_termios())
+        * (they will be reenabled in set_termios())
         */
        serial8250_clear_fifos(up);
 
@@ -1536,6 +1633,26 @@ static int serial8250_startup(struct uart_port *port)
                        up->port.mctrl |= TIOCM_OUT2;
 
        serial8250_set_mctrl(&up->port, up->port.mctrl);
+
+       /*
+        * 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",
+                                port->line);
+               }
+       } else {
+               up->bugs &= ~UART_BUG_TXEN;
+       }
+
        spin_unlock_irqrestore(&up->port.lock, flags);
 
        /*
@@ -1645,22 +1762,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
-               cval = 0x00;
+               cval = UART_LCR_WLEN5;
                break;
        case CS6:
-               cval = 0x01;
+               cval = UART_LCR_WLEN6;
                break;
        case CS7:
-               cval = 0x02;
+               cval = UART_LCR_WLEN7;
                break;
        default:
        case CS8:
-               cval = 0x03;
+               cval = UART_LCR_WLEN8;
                break;
        }
 
        if (termios->c_cflag & CSTOPB)
-               cval |= 0x04;
+               cval |= UART_LCR_STOP;
        if (termios->c_cflag & PARENB)
                cval |= UART_LCR_PARITY;
        if (!(termios->c_cflag & PARODD))
@@ -1677,12 +1794,9 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
        quot = serial8250_get_divisor(port, baud);
 
        /*
-        * Work around a bug in the Oxford Semiconductor 952 rev B
-        * chip which causes it to seriously miscalculate baud rates
-        * when DLL is 0.
+        * Oxford Semi 952 rev B workaround
         */
-       if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
-           up->rev == 0x5201)
+       if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
                quot ++;
 
        if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
@@ -1749,7 +1863,8 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
         * CTS flow control flag and modem status interrupts
         */
        up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+       if (!(up->bugs & UART_BUG_NOMSR) &&
+                       UART_ENABLE_MS(&up->port, termios->c_cflag))
                up->ier |= UART_IER_MSI;
        if (up->capabilities & UART_CAP_UUE)
                up->ier |= UART_IER_UUE | UART_IER_RTOIE;
@@ -1777,8 +1892,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
                serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
        }
 
-       serial_outp(up, UART_DLL, quot & 0xff);         /* LS of divisor */
-       serial_outp(up, UART_DLM, quot >> 8);           /* MS of divisor */
+       serial_dl_write(up, quot);
 
        /*
         * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@@ -1821,6 +1935,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
        int ret = 0;
 
        switch (up->port.iotype) {
+       case UPIO_AU:
+               size = 0x100000;
+               /* fall thru */
        case UPIO_MEM:
                if (!up->port.mapbase)
                        break;
@@ -1853,6 +1970,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
        unsigned int size = 8 << up->port.regshift;
 
        switch (up->port.iotype) {
+       case UPIO_AU:
+               size = 0x100000;
+               /* fall thru */
        case UPIO_MEM:
                if (!up->port.mapbase)
                        break;
@@ -1940,12 +2060,6 @@ static void serial8250_config_port(struct uart_port *port, int flags)
        int probeflags = PROBE_ANY;
        int ret;
 
-       /*
-        * Don't probe for MCA ports on non-MCA machines.
-        */
-       if (up->port.flags & UPF_BOOT_ONLYMCA && !MCA_bus)
-               return;
-
        /*
         * Find the region that we can probe for.  This in turn
         * tells us whether we can probe for the type of port.
@@ -2022,7 +2136,7 @@ static void __init serial8250_isa_init_ports(void)
                return;
        first = 0;
 
-       for (i = 0; i < UART_NR; i++) {
+       for (i = 0; i < nr_uarts; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
                up->port.line = i;
@@ -2040,7 +2154,8 @@ static void __init serial8250_isa_init_ports(void)
                up->port.ops = &serial8250_pops;
        }
 
-       for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port);
+       for (i = 0, up = serial8250_ports;
+            i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
             i++, up++) {
                up->port.iobase   = old_serial_port[i].port;
                up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
@@ -2062,7 +2177,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 
        serial8250_isa_init_ports();
 
-       for (i = 0; i < UART_NR; i++) {
+       for (i = 0; i < nr_uarts; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
                up->port.dev = dev;
@@ -2077,7 +2192,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 /*
  *     Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct uart_8250_port *up)
+static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
        unsigned int status, tmout = 10000;
 
@@ -2091,17 +2206,27 @@ static inline void wait_for_xmitr(struct uart_8250_port *up)
                if (--tmout == 0)
                        break;
                udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+       } while ((status & bits) != bits);
 
        /* Wait up to 1s for flow control if necessary */
        if (up->port.flags & UPF_CONS_FLOW) {
                tmout = 1000000;
-               while (--tmout &&
-                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+               while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
                        udelay(1);
+                       if ((tmout % 1000) == 0)
+                               touch_nmi_watchdog();
+               }
        }
 }
 
+static void serial8250_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+       wait_for_xmitr(up, UART_LSR_THRE);
+       serial_out(up, UART_TX, ch);
+}
+
 /*
  *     Print a string to the serial port trying not to disturb
  *     any possible real use of the port...
@@ -2112,11 +2237,19 @@ static void
 serial8250_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct uart_8250_port *up = &serial8250_ports[co->index];
+       unsigned long flags;
        unsigned int ier;
-       int i;
+       int locked = 1;
+
+       touch_nmi_watchdog();
+
+       if (oops_in_progress) {
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       } else
+               spin_lock_irqsave(&up->port.lock, flags);
 
        /*
-        *      First save the UER then disable the interrupts
+        *      First save the IER then disable the interrupts
         */
        ier = serial_in(up, UART_IER);
 
@@ -2125,29 +2258,17 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
        else
                serial_out(up, UART_IER, 0);
 
-       /*
-        *      Now, do each character
-        */
-       for (i = 0; i < count; i++, s++) {
-               wait_for_xmitr(up);
-
-               /*
-                *      Send the character out.
-                *      If a LF, also do CR...
-                */
-               serial_out(up, UART_TX, *s);
-               if (*s == 10) {
-                       wait_for_xmitr(up);
-                       serial_out(up, UART_TX, 13);
-               }
-       }
+       uart_console_write(&up->port, s, count, serial8250_console_putchar);
 
        /*
         *      Finally, wait for transmitter to become empty
         *      and restore the IER
         */
-       wait_for_xmitr(up);
+       wait_for_xmitr(up, BOTH_EMPTY);
        serial_out(up, UART_IER, ier);
+
+       if (locked)
+               spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
 static int serial8250_console_setup(struct console *co, char *options)
@@ -2163,7 +2284,7 @@ static int serial8250_console_setup(struct console *co, char *options)
         * if so, search for the first available port that does have
         * console support.
         */
-       if (co->index >= UART_NR)
+       if (co->index >= nr_uarts)
                co->index = 0;
        port = &serial8250_ports[co->index].port;
        if (!port->iobase && !port->membase)
@@ -2199,11 +2320,9 @@ static int __init find_port(struct uart_port *p)
        int line;
        struct uart_port *port;
 
-       for (line = 0; line < UART_NR; line++) {
+       for (line = 0; line < nr_uarts; line++) {
                port = &serial8250_ports[line].port;
-               if (p->iotype == port->iotype &&
-                   p->iobase == port->iobase &&
-                   p->membase == port->membase)
+               if (uart_match_port(p, port))
                        return line;
        }
        return -ENODEV;
@@ -2245,6 +2364,12 @@ static struct uart_driver serial8250_reg = {
        .cons                   = SERIAL8250_CONSOLE,
 };
 
+/*
+ * early_serial_setup - early registration for 8250 ports
+ *
+ * Setup an 8250 port structure prior to console initialisation.  Use
+ * after console initialisation will cause undefined behaviour.
+ */
 int __init early_serial_setup(struct uart_port *port)
 {
        if (port->line >= ARRAY_SIZE(serial8250_ports))
@@ -2285,14 +2410,15 @@ void serial8250_resume_port(int line)
  * list is terminated with a zero flags entry, which means we expect
  * all entries to have at least UPF_BOOT_AUTOCONF set.
  */
-static int __devinit serial8250_probe(struct device *dev)
+static int __devinit serial8250_probe(struct platform_device *dev)
 {
-       struct plat_serial8250_port *p = dev->platform_data;
+       struct plat_serial8250_port *p = dev->dev.platform_data;
        struct uart_port port;
+       int ret, i;
 
        memset(&port, 0, sizeof(struct uart_port));
 
-       for (; p && p->flags != 0; p++) {
+       for (i = 0; p && p->flags != 0; p++, i++) {
                port.iobase     = p->iobase;
                port.membase    = p->membase;
                port.irq        = p->irq;
@@ -2301,10 +2427,16 @@ static int __devinit serial8250_probe(struct device *dev)
                port.iotype     = p->iotype;
                port.flags      = p->flags;
                port.mapbase    = p->mapbase;
-               port.dev        = dev;
+               port.hub6       = p->hub6;
+               port.dev        = &dev->dev;
                if (share_irqs)
                        port.flags |= UPF_SHARE_IRQ;
-               serial8250_register_port(&port);
+               ret = serial8250_register_port(&port);
+               if (ret < 0) {
+                       dev_err(&dev->dev, "unable to register port at index %d "
+                               "(IO%lx MEM%lx IRQ%d): %d\n", i,
+                               p->iobase, p->mapbase, p->irq, ret);
+               }
        }
        return 0;
 }
@@ -2312,60 +2444,56 @@ static int __devinit serial8250_probe(struct device *dev)
 /*
  * Remove serial ports registered against a platform device.
  */
-static int __devexit serial8250_remove(struct device *dev)
+static int __devexit serial8250_remove(struct platform_device *dev)
 {
        int i;
 
-       for (i = 0; i < UART_NR; i++) {
+       for (i = 0; i < nr_uarts; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
-               if (up->port.dev == dev)
+               if (up->port.dev == &dev->dev)
                        serial8250_unregister_port(i);
        }
        return 0;
 }
 
-static int serial8250_suspend(struct device *dev, pm_message_t state, u32 level)
+static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
 {
        int i;
 
-       if (level != SUSPEND_DISABLE)
-               return 0;
-
        for (i = 0; i < UART_NR; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == dev)
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
                        uart_suspend_port(&serial8250_reg, &up->port);
        }
 
        return 0;
 }
 
-static int serial8250_resume(struct device *dev, u32 level)
+static int serial8250_resume(struct platform_device *dev)
 {
        int i;
 
-       if (level != RESUME_ENABLE)
-               return 0;
-
        for (i = 0; i < UART_NR; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == dev)
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
                        uart_resume_port(&serial8250_reg, &up->port);
        }
 
        return 0;
 }
 
-static struct device_driver serial8250_isa_driver = {
-       .name           = "serial8250",
-       .bus            = &platform_bus_type,
+static struct platform_driver serial8250_isa_driver = {
        .probe          = serial8250_probe,
        .remove         = __devexit_p(serial8250_remove),
        .suspend        = serial8250_suspend,
        .resume         = serial8250_resume,
+       .driver         = {
+               .name   = "serial8250",
+               .owner  = THIS_MODULE,
+       },
 };
 
 /*
@@ -2379,7 +2507,7 @@ static struct platform_device *serial8250_isa_devs;
  * 16x50 serial ports to be configured at run-time, to support PCMCIA
  * modems and PCI multiport cards.
  */
-static DECLARE_MUTEX(serial_sem);
+static DEFINE_MUTEX(serial_mutex);
 
 static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
 {
@@ -2388,7 +2516,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
        /*
         * First, find a port entry which matches.
         */
-       for (i = 0; i < UART_NR; i++)
+       for (i = 0; i < nr_uarts; i++)
                if (uart_match_port(&serial8250_ports[i].port, port))
                        return &serial8250_ports[i];
 
@@ -2397,7 +2525,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
         * free entry.  We look for one which hasn't been previously
         * used (indicated by zero iobase).
         */
-       for (i = 0; i < UART_NR; i++)
+       for (i = 0; i < nr_uarts; i++)
                if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
                    serial8250_ports[i].port.iobase == 0)
                        return &serial8250_ports[i];
@@ -2406,7 +2534,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
         * That also failed.  Last resort is to find any entry which
         * doesn't have a real port associated with it.
         */
-       for (i = 0; i < UART_NR; i++)
+       for (i = 0; i < nr_uarts; i++)
                if (serial8250_ports[i].port.type == PORT_UNKNOWN)
                        return &serial8250_ports[i];
 
@@ -2434,7 +2562,7 @@ int serial8250_register_port(struct uart_port *port)
        if (port->uartclk == 0)
                return -EINVAL;
 
-       down(&serial_sem);
+       mutex_lock(&serial_mutex);
 
        uart = serial8250_find_match_or_unused(port);
        if (uart) {
@@ -2456,7 +2584,7 @@ int serial8250_register_port(struct uart_port *port)
                if (ret == 0)
                        ret = uart->port.line;
        }
-       up(&serial_sem);
+       mutex_unlock(&serial_mutex);
 
        return ret;
 }
@@ -2473,7 +2601,7 @@ void serial8250_unregister_port(int line)
 {
        struct uart_8250_port *uart = &serial8250_ports[line];
 
-       down(&serial_sem);
+       mutex_lock(&serial_mutex);
        uart_remove_one_port(&serial8250_reg, &uart->port);
        if (serial8250_isa_devs) {
                uart->port.flags &= ~UPF_BOOT_AUTOCONF;
@@ -2483,7 +2611,7 @@ void serial8250_unregister_port(int line)
        } else {
                uart->port.dev = NULL;
        }
-       up(&serial_sem);
+       mutex_unlock(&serial_mutex);
 }
 EXPORT_SYMBOL(serial8250_unregister_port);
 
@@ -2491,8 +2619,11 @@ static int __init serial8250_init(void)
 {
        int ret, i;
 
+       if (nr_uarts > UART_NR)
+               nr_uarts = UART_NR;
+
        printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ "
-               "%d ports, IRQ sharing %sabled\n", (int) UART_NR,
+               "%d ports, IRQ sharing %sabled\n", nr_uarts,
                share_irqs ? "en" : "dis");
 
        for (i = 0; i < NR_IRQS; i++)
@@ -2502,21 +2633,27 @@ static int __init serial8250_init(void)
        if (ret)
                goto out;
 
-       serial8250_isa_devs = platform_device_register_simple("serial8250",
-                                                             -1, NULL, 0);
-       if (IS_ERR(serial8250_isa_devs)) {
-               ret = PTR_ERR(serial8250_isa_devs);
-               goto unreg;
+       serial8250_isa_devs = platform_device_alloc("serial8250",
+                                                   PLAT8250_DEV_LEGACY);
+       if (!serial8250_isa_devs) {
+               ret = -ENOMEM;
+               goto unreg_uart_drv;
        }
 
+       ret = platform_device_add(serial8250_isa_devs);
+       if (ret)
+               goto put_dev;
+
        serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
 
-       ret = driver_register(&serial8250_isa_driver);
+       ret = platform_driver_register(&serial8250_isa_driver);
        if (ret == 0)
                goto out;
 
-       platform_device_unregister(serial8250_isa_devs);
- unreg:
+       platform_device_del(serial8250_isa_devs);
+ put_dev:
+       platform_device_put(serial8250_isa_devs);
+ unreg_uart_drv:
        uart_unregister_driver(&serial8250_reg);
  out:
        return ret;
@@ -2533,7 +2670,7 @@ static void __exit serial8250_exit(void)
         */
        serial8250_isa_devs = NULL;
 
-       driver_unregister(&serial8250_isa_driver);
+       platform_driver_unregister(&serial8250_isa_driver);
        platform_device_unregister(isa_dev);
 
        uart_unregister_driver(&serial8250_reg);
@@ -2552,87 +2689,11 @@ module_param(share_irqs, uint, 0644);
 MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
        " (unsafe)");
 
+module_param(nr_uarts, uint, 0644);
+MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
+
 #ifdef CONFIG_SERIAL_8250_RSA
 module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
 MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
 #endif
 MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
-
-/**
- *     register_serial - configure a 16x50 serial port at runtime
- *     @req: request structure
- *
- *     Configure the serial port specified by the request. If the
- *     port exists and is in use an error is returned. If the port
- *     is not currently in the table it is added.
- *
- *     The port is then probed and if necessary the IRQ is autodetected
- *     If this fails an error is returned.
- *
- *     On success the port is ready to use and the line number is returned.
- *
- *     Note: this function is deprecated - use serial8250_register_port
- *     instead.
- */
-int register_serial(struct serial_struct *req)
-{
-       struct uart_port port;
-
-       port.iobase   = req->port;
-       port.membase  = req->iomem_base;
-       port.irq      = req->irq;
-       port.uartclk  = req->baud_base * 16;
-       port.fifosize = req->xmit_fifo_size;
-       port.regshift = req->iomem_reg_shift;
-       port.iotype   = req->io_type;
-       port.flags    = req->flags | UPF_BOOT_AUTOCONF;
-       port.mapbase  = req->iomap_base;
-       port.dev      = NULL;
-
-       if (share_irqs)
-               port.flags |= UPF_SHARE_IRQ;
-
-       if (HIGH_BITS_OFFSET)
-               port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
-
-       /*
-        * If a clock rate wasn't specified by the low level driver, then
-        * default to the standard clock rate.  This should be 115200 (*16)
-        * and should not depend on the architecture's BASE_BAUD definition.
-        * However, since this API will be deprecated, it's probably a
-        * better idea to convert the drivers to use the new API
-        * (serial8250_register_port and serial8250_unregister_port).
-        */
-       if (port.uartclk == 0) {
-               printk(KERN_WARNING
-                      "Serial: registering port at [%08x,%08lx,%p] irq %d with zero baud_base\n",
-                      port.iobase, port.mapbase, port.membase, port.irq);
-               printk(KERN_WARNING "Serial: see %s:%d for more information\n",
-                      __FILE__, __LINE__);
-               dump_stack();
-
-               /*
-                * Fix it up for now, but this is only a temporary measure.
-                */
-               port.uartclk = BASE_BAUD * 16;
-       }
-
-       return serial8250_register_port(&port);
-}
-EXPORT_SYMBOL(register_serial);
-
-/**
- *     unregister_serial - remove a 16x50 serial port at runtime
- *     @line: serial line number
- *
- *     Remove one serial port.  This may not be called from interrupt
- *     context.  We hand the port back to our local PM control.
- *
- *     Note: this function is deprecated - use serial8250_unregister_port
- *     instead.
- */
-void unregister_serial(int line)
-{
-       serial8250_unregister_port(line);
-}
-EXPORT_SYMBOL(unregister_serial);