]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/serial/8250.c
Revert "Call init_workqueues before pre smp initcalls."
[linux-2.6-omap-h63xx.git] / drivers / serial / 8250.c
index d4104a3bbe87cd7400a68f083369c41da3396d5b..303272af386ef4ac307517d6df654759cbc23d43 100644 (file)
@@ -156,11 +156,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.
@@ -1545,15 +1549,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) {
@@ -1577,14 +1609,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 */
@@ -2223,9 +2269,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 +2324,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 +2378,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:
@@ -2440,7 +2493,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)
@@ -2960,7 +3013,7 @@ 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;
@@ -2996,15 +3049,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;
 }