serial, 8250: calculate irqflags bitmask before loop
[safe/jmp/linux-2.6] / drivers / serial / 8250.c
index d3ca7d3..b75e63e 100644 (file)
@@ -64,6 +64,8 @@ static int serial_index(struct uart_port *port)
        return (serial8250_reg.minor - 64) + port->line;
 }
 
+static unsigned int skip_txen_test; /* force skip of txen test at init time */
+
 /*
  * Debugging.
  */
@@ -137,6 +139,7 @@ struct uart_8250_port {
        unsigned char           mcr;
        unsigned char           mcr_mask;       /* mask of user bits */
        unsigned char           mcr_force;      /* mask of forced bits */
+       unsigned char           cur_iotype;     /* Running I/O type */
 
        /*
         * Some bits in registers are cleared on a read, so they must
@@ -156,11 +159,15 @@ struct uart_8250_port {
 };
 
 struct irq_info {
-       spinlock_t              lock;
+       struct                  hlist_node node;
+       int                     irq;
+       spinlock_t              lock;   /* Protects list not the hash */
        struct list_head        *head;
 };
 
-static struct irq_info irq_lists[NR_IRQS];
+#define NR_IRQ_HASH            32      /* Can be adjusted later */
+static struct hlist_head irq_lists[NR_IRQ_HASH];
+static DEFINE_MUTEX(hash_mutex);       /* Used to walk the hash */
 
 /*
  * Here we define the default xmit fifo size used for each type of UART.
@@ -275,6 +282,20 @@ static const struct serial8250_config uart_config[] = {
                .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
                .flags          = UART_CAP_FIFO,
        },
+       [PORT_OCTEON] = {
+               .name           = "OCTEON",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_AR7] = {
+               .name           = "AR7",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
+       },
 };
 
 #if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -299,16 +320,16 @@ static const u8 au_io_out_map[] = {
 };
 
 /* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_AU)
+       if (p->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)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_AU)
+       if (p->iotype != UPIO_AU)
                return offset;
        return au_io_out_map[offset];
 }
@@ -337,16 +358,16 @@ static const u8
                [UART_SCR]      = 0x2c
        };
 
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_RM9000)
+       if (p->iotype != UPIO_RM9000)
                return offset;
        return regmap_in[offset];
 }
 
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_RM9000)
+       if (p->iotype != UPIO_RM9000)
                return offset;
        return regmap_out[offset];
 }
@@ -359,108 +380,173 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
 
 #endif
 
-static unsigned int serial_in(struct uart_8250_port *up, int offset)
+static unsigned int hub6_serial_in(struct uart_port *p, int offset)
 {
-       unsigned int tmp;
-       offset = map_8250_in_reg(up, offset) << up->port.regshift;
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       return inb(p->iobase + 1);
+}
 
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               return inb(up->port.iobase + 1);
+static void hub6_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       outb(value, p->iobase + 1);
+}
 
-       case UPIO_MEM:
-       case UPIO_DWAPB:
-               return readb(up->port.membase + offset);
+static unsigned int mem_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readb(p->membase + offset);
+}
 
-       case UPIO_RM9000:
-       case UPIO_MEM32:
-               return readl(up->port.membase + offset);
+static void mem_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writeb(value, p->membase + offset);
+}
+
+static void mem32_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writel(value, p->membase + offset);
+}
+
+static unsigned int mem32_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readl(p->membase + offset);
+}
 
 #ifdef CONFIG_SERIAL_8250_AU1X00
-       case UPIO_AU:
-               return __raw_readl(up->port.membase + offset);
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       __raw_writel(value, p->membase + offset);
+}
 #endif
 
-       case UPIO_TSI:
-               if (offset == UART_IIR) {
-                       tmp = readl(up->port.membase + (UART_IIR & ~3));
-                       return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
-               } else
-                       return readb(up->port.membase + offset);
+static unsigned int tsi_serial_in(struct uart_port *p, int offset)
+{
+       unsigned int tmp;
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       if (offset == UART_IIR) {
+               tmp = readl(p->membase + (UART_IIR & ~3));
+               return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
+       } else
+               return readb(p->membase + offset);
+}
 
-       default:
-               return inb(up->port.iobase + offset);
-       }
+static void tsi_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+               writeb(value, p->membase + offset);
 }
 
-static void
-serial_out(struct uart_8250_port *up, int offset, int value)
+static void dwapb_serial_out(struct uart_port *p, int offset, int value)
 {
-       /* Save the offset before it's remapped */
        int save_offset = offset;
-       offset = map_8250_out_reg(up, offset) << up->port.regshift;
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       /* Save the LCR value so it can be re-written when a
+        * Busy Detect interrupt occurs. */
+       if (save_offset == UART_LCR) {
+               struct uart_8250_port *up = (struct uart_8250_port *)p;
+               up->lcr = value;
+       }
+       writeb(value, p->membase + offset);
+       /* Read the IER to ensure any interrupt is cleared before
+        * returning from ISR. */
+       if (save_offset == UART_TX || save_offset == UART_IER)
+               value = p->serial_in(p, UART_IER);
+}
 
-       switch (up->port.iotype) {
+static unsigned int io_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return inb(p->iobase + offset);
+}
+
+static void io_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(value, p->iobase + offset);
+}
+
+static void set_io_from_upio(struct uart_port *p)
+{
+       struct uart_8250_port *up = (struct uart_8250_port *)p;
+       switch (p->iotype) {
        case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               outb(value, up->port.iobase + 1);
+               p->serial_in = hub6_serial_in;
+               p->serial_out = hub6_serial_out;
                break;
 
        case UPIO_MEM:
-               writeb(value, up->port.membase + offset);
+               p->serial_in = mem_serial_in;
+               p->serial_out = mem_serial_out;
                break;
 
        case UPIO_RM9000:
        case UPIO_MEM32:
-               writel(value, up->port.membase + offset);
+               p->serial_in = mem32_serial_in;
+               p->serial_out = mem32_serial_out;
                break;
 
 #ifdef CONFIG_SERIAL_8250_AU1X00
        case UPIO_AU:
-               __raw_writel(value, up->port.membase + offset);
+               p->serial_in = au_serial_in;
+               p->serial_out = au_serial_out;
                break;
 #endif
        case UPIO_TSI:
-               if (!((offset == UART_IER) && (value & UART_IER_UUE)))
-                       writeb(value, up->port.membase + offset);
+               p->serial_in = tsi_serial_in;
+               p->serial_out = tsi_serial_out;
                break;
 
        case UPIO_DWAPB:
-               /* Save the LCR value so it can be re-written when a
-                * Busy Detect interrupt occurs. */
-               if (save_offset == UART_LCR)
-                       up->lcr = value;
-               writeb(value, up->port.membase + offset);
-               /* Read the IER to ensure any interrupt is cleared before
-                * returning from ISR. */
-               if (save_offset == UART_TX || save_offset == UART_IER)
-                       value = serial_in(up, UART_IER);
+               p->serial_in = mem_serial_in;
+               p->serial_out = dwapb_serial_out;
                break;
 
        default:
-               outb(value, up->port.iobase + offset);
+               p->serial_in = io_serial_in;
+               p->serial_out = io_serial_out;
+               break;
        }
+       /* Remember loaded iotype */
+       up->cur_iotype = p->iotype;
 }
 
 static void
 serial_out_sync(struct uart_8250_port *up, int offset, int value)
 {
-       switch (up->port.iotype) {
+       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:
-               serial_out(up, offset, value);
-               serial_in(up, UART_LCR);        /* safe, no side-effects */
+               p->serial_out(p, offset, value);
+               p->serial_in(p, UART_LCR);      /* safe, no side-effects */
                break;
        default:
-               serial_out(up, offset, value);
+               p->serial_out(p, offset, value);
        }
 }
 
+#define serial_in(up, offset)          \
+       (up->port.serial_in(&(up)->port, (offset)))
+#define serial_out(up, offset, value)  \
+       (up->port.serial_out(&(up)->port, (offset), (value)))
 /*
  * We used to support using pause I/O for certain machines.  We
  * haven't supported this for a while, but just in case it's badly
@@ -1003,7 +1089,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
                return;
 
-       DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
+       DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ",
                       serial_index(&up->port), up->port.iobase, up->port.membase);
 
        /*
@@ -1298,7 +1384,7 @@ 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->port.tty;
+       struct tty_struct *tty = up->port.state->port.tty;
        unsigned char ch, lsr = *status;
        int max_count = 256;
        char flag;
@@ -1373,7 +1459,7 @@ ignore_char:
 
 static void transmit_chars(struct uart_8250_port *up)
 {
-       struct circ_buf *xmit = &up->port.info->xmit;
+       struct circ_buf *xmit = &up->port.state->xmit;
        int count;
 
        if (up->port.x_char) {
@@ -1416,7 +1502,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
        status |= up->msr_saved_flags;
        up->msr_saved_flags = 0;
        if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
-           up->port.info != NULL) {
+           up->port.state != NULL) {
                if (status & UART_MSR_TERI)
                        up->port.icount.rng++;
                if (status & UART_MSR_DDSR)
@@ -1426,7 +1512,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
                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.state->port.delta_msr_wait);
        }
 
        return status;
@@ -1545,15 +1631,43 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
                BUG_ON(i->head != &up->list);
                i->head = NULL;
        }
-
        spin_unlock_irq(&i->lock);
+       /* List empty so throw away the hash node */
+       if (i->head == NULL) {
+               hlist_del(&i->node);
+               kfree(i);
+       }
 }
 
 static int serial_link_irq_chain(struct uart_8250_port *up)
 {
-       struct irq_info *i = irq_lists + up->port.irq;
+       struct hlist_head *h;
+       struct hlist_node *n;
+       struct irq_info *i;
        int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
 
+       mutex_lock(&hash_mutex);
+
+       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
+
+       hlist_for_each(n, h) {
+               i = hlist_entry(n, struct irq_info, node);
+               if (i->irq == up->port.irq)
+                       break;
+       }
+
+       if (n == NULL) {
+               i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
+               if (i == NULL) {
+                       mutex_unlock(&hash_mutex);
+                       return -ENOMEM;
+               }
+               spin_lock_init(&i->lock);
+               i->irq = up->port.irq;
+               hlist_add_head(&i->node, h);
+       }
+       mutex_unlock(&hash_mutex);
+
        spin_lock_irq(&i->lock);
 
        if (i->head) {
@@ -1565,7 +1679,7 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
                INIT_LIST_HEAD(&up->list);
                i->head = &up->list;
                spin_unlock_irq(&i->lock);
-
+               irq_flags |= up->port.irqflags;
                ret = request_irq(up->port.irq, serial8250_interrupt,
                                  irq_flags, "serial", i);
                if (ret < 0)
@@ -1577,14 +1691,28 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
 
 static void serial_unlink_irq_chain(struct uart_8250_port *up)
 {
-       struct irq_info *i = irq_lists + up->port.irq;
+       struct irq_info *i;
+       struct hlist_node *n;
+       struct hlist_head *h;
+
+       mutex_lock(&hash_mutex);
 
+       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
+
+       hlist_for_each(n, h) {
+               i = hlist_entry(n, struct irq_info, node);
+               if (i->irq == up->port.irq)
+                       break;
+       }
+
+       BUG_ON(n == NULL);
        BUG_ON(i->head == NULL);
 
        if (list_empty(i->head))
                free_irq(up->port.irq, i);
 
        serial_do_unlink(i, up);
+       mutex_unlock(&hash_mutex);
 }
 
 /* Base timer interval for polling */
@@ -1638,7 +1766,7 @@ static void serial8250_backup_timeout(unsigned long data)
        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.info->xmit) || up->port.x_char) &&
+           (!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;
@@ -1822,6 +1950,9 @@ static int serial8250_startup(struct uart_port *port)
        up->capabilities = uart_config[up->port.type].flags;
        up->mcr = 0;
 
+       if (up->port.iotype != up->cur_iotype)
+               set_io_from_upio(port);
+
        if (up->port.type == PORT_16C950) {
                /* Wake up and initialize UART */
                up->acr = 0;
@@ -1897,7 +2028,7 @@ 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)
+               if (up->port.irqflags & IRQF_SHARED)
                        disable_irq_nosync(up->port.irq);
 
                wait_for_xmitr(up, UART_LSR_THRE);
@@ -1910,7 +2041,7 @@ static int serial8250_startup(struct uart_port *port)
                iir = serial_in(up, UART_IIR);
                serial_out(up, UART_IER, 0);
 
-               if (up->port.flags & UPF_SHARE_IRQ)
+               if (up->port.irqflags & IRQF_SHARED)
                        enable_irq(up->port.irq);
                spin_unlock_irqrestore(&up->port.lock, flags);
 
@@ -1968,6 +2099,20 @@ 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.
@@ -1987,6 +2132,7 @@ static int serial8250_startup(struct uart_port *port)
                up->bugs &= ~UART_BUG_TXEN;
        }
 
+dont_test_tx_en:
        spin_unlock_irqrestore(&up->port.lock, flags);
 
        /*
@@ -2128,7 +2274,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
        /*
         * Ask the core to calculate the divisor for us.
         */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       baud = uart_get_baud_rate(port, termios, old,
+                                 port->uartclk / 16 / 0xffff,
+                                 port->uartclk / 16);
        quot = serial8250_get_divisor(port, baud);
 
        /*
@@ -2223,9 +2371,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);
@@ -2278,18 +2426,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:
@@ -2323,12 +2480,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:
@@ -2426,6 +2581,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
        if (ret < 0)
                probeflags &= ~PROBE_RSA;
 
+       if (up->port.iotype != up->cur_iotype)
+               set_io_from_upio(port);
+
        if (flags & UART_CONFIG_TYPE)
                autoconfig(up, probeflags);
        if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
@@ -2440,7 +2598,7 @@ static void serial8250_config_port(struct uart_port *port, int flags)
 static int
 serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
-       if (ser->irq >= NR_IRQS || ser->irq < 0 ||
+       if (ser->irq >= nr_irqs || ser->irq < 0 ||
            ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
            ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
            ser->type == PORT_STARTECH)
@@ -2488,7 +2646,7 @@ static void __init serial8250_isa_init_ports(void)
 {
        struct uart_8250_port *up;
        static int first = 1;
-       int i;
+       int i, irqflag = 0;
 
        if (!first)
                return;
@@ -2512,19 +2670,23 @@ static void __init serial8250_isa_init_ports(void)
                up->port.ops = &serial8250_pops;
        }
 
+       if (share_irqs)
+               irqflag = IRQF_SHARED;
+
        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);
+               up->port.irqflags = old_serial_port[i].irqflags;
                up->port.uartclk  = old_serial_port[i].baud_base * 16;
                up->port.flags    = old_serial_port[i].flags;
                up->port.hub6     = old_serial_port[i].hub6;
                up->port.membase  = old_serial_port[i].iomem_base;
                up->port.iotype   = old_serial_port[i].io_type;
                up->port.regshift = old_serial_port[i].iomem_reg_shift;
-               if (share_irqs)
-                       up->port.flags |= UPF_SHARE_IRQ;
+               set_io_from_upio(&up->port);
+               up->port.irqflags |= irqflag;
        }
 }
 
@@ -2533,6 +2695,11 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 {
        int i;
 
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+               up->cur_iotype = 0xFF;
+       }
+
        serial8250_isa_init_ports();
 
        for (i = 0; i < nr_uarts; i++) {
@@ -2699,12 +2866,33 @@ static struct uart_driver serial8250_reg = {
  */
 int __init early_serial_setup(struct uart_port *port)
 {
+       struct uart_port *p;
+
        if (port->line >= ARRAY_SIZE(serial8250_ports))
                return -ENODEV;
 
        serial8250_isa_init_ports();
-       serial8250_ports[port->line].port       = *port;
-       serial8250_ports[port->line].port.ops   = &serial8250_pops;
+       p = &serial8250_ports[port->line].port;
+       p->iobase       = port->iobase;
+       p->membase      = port->membase;
+       p->irq          = port->irq;
+       p->irqflags     = port->irqflags;
+       p->uartclk      = port->uartclk;
+       p->fifosize     = port->fifosize;
+       p->regshift     = port->regshift;
+       p->iotype       = port->iotype;
+       p->flags        = port->flags;
+       p->mapbase      = port->mapbase;
+       p->private_data = port->private_data;
+       p->type         = port->type;
+       p->line         = port->line;
+
+       set_io_from_upio(p);
+       if (port->serial_in)
+               p->serial_in = port->serial_in;
+       if (port->serial_out)
+               p->serial_out = port->serial_out;
+
        return 0;
 }
 
@@ -2754,14 +2942,18 @@ static int __devinit serial8250_probe(struct platform_device *dev)
 {
        struct plat_serial8250_port *p = dev->dev.platform_data;
        struct uart_port port;
-       int ret, i;
+       int ret, i, irqflag = 0;
 
        memset(&port, 0, sizeof(struct uart_port));
 
+       if (share_irqs)
+               irqflag = IRQF_SHARED;
+
        for (i = 0; p && p->flags != 0; p++, i++) {
                port.iobase             = p->iobase;
                port.membase            = p->membase;
                port.irq                = p->irq;
+               port.irqflags           = p->irqflags;
                port.uartclk            = p->uartclk;
                port.regshift           = p->regshift;
                port.iotype             = p->iotype;
@@ -2769,9 +2961,11 @@ static int __devinit serial8250_probe(struct platform_device *dev)
                port.mapbase            = p->mapbase;
                port.hub6               = p->hub6;
                port.private_data       = p->private_data;
+               port.type               = p->type;
+               port.serial_in          = p->serial_in;
+               port.serial_out         = p->serial_out;
                port.dev                = &dev->dev;
-               if (share_irqs)
-                       port.flags |= UPF_SHARE_IRQ;
+               port.irqflags           |= irqflag;
                ret = serial8250_register_port(&port);
                if (ret < 0) {
                        dev_err(&dev->dev, "unable to register port at index %d "
@@ -2913,6 +3107,7 @@ int serial8250_register_port(struct uart_port *port)
                uart->port.iobase       = port->iobase;
                uart->port.membase      = port->membase;
                uart->port.irq          = port->irq;
+               uart->port.irqflags     = port->irqflags;
                uart->port.uartclk      = port->uartclk;
                uart->port.fifosize     = port->fifosize;
                uart->port.regshift     = port->regshift;
@@ -2923,6 +3118,20 @@ int serial8250_register_port(struct uart_port *port)
                if (port->dev)
                        uart->port.dev = port->dev;
 
+               if (port->flags & UPF_FIXED_TYPE) {
+                       uart->port.type = port->type;
+                       uart->port.fifosize = uart_config[port->type].fifo_size;
+                       uart->capabilities = uart_config[port->type].flags;
+                       uart->tx_loadsz = uart_config[port->type].tx_loadsz;
+               }
+
+               set_io_from_upio(&uart->port);
+               /* Possibly override default I/O functions.  */
+               if (port->serial_in)
+                       uart->port.serial_in = port->serial_in;
+               if (port->serial_out)
+                       uart->port.serial_out = port->serial_out;
+
                ret = uart_add_one_port(&serial8250_reg, &uart->port);
                if (ret == 0)
                        ret = uart->port.line;
@@ -2960,18 +3169,15 @@ EXPORT_SYMBOL(serial8250_unregister_port);
 
 static int __init serial8250_init(void)
 {
-       int ret, i;
+       int ret;
 
        if (nr_uarts > UART_NR)
                nr_uarts = UART_NR;
 
-       printk(KERN_INFO "Serial: 8250/16550 driver"
+       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
@@ -2999,15 +3205,15 @@ static int __init serial8250_init(void)
                goto out;
 
        platform_device_del(serial8250_isa_devs);
- put_dev:
+put_dev:
        platform_device_put(serial8250_isa_devs);
- unreg_uart_drv:
+unreg_uart_drv:
 #ifdef CONFIG_SPARC
        sunserial_unregister_minors(&serial8250_reg, UART_NR);
 #else
        uart_unregister_driver(&serial8250_reg);
 #endif
- out:
+out:
        return ret;
 }
 
@@ -3048,6 +3254,9 @@ MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
 module_param(nr_uarts, uint, 0644);
 MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
 
+module_param(skip_txen_test, uint, 0644);
+MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
+
 #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");