diff -urN linux-2.4.17/drivers/char/serial.c linux-2.4.17-serial/drivers/char/serial.c --- linux-2.4.17/drivers/char/serial.c Sun Dec 23 16:23:39 2001 +++ linux-2.4.17-serial/drivers/char/serial.c Sun Jan 6 23:43:51 2002 @@ -198,6 +198,7 @@ #include #include #include +#include #if (LINUX_VERSION_CODE >= 131343) #include #endif @@ -1210,7 +1211,7 @@ if (!page) return -ENOMEM; - save_flags(flags); cli(); + spin_lock_irqsave( &info->irq_spinlock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -1448,11 +1449,11 @@ change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return 0; errout: - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return retval; } @@ -1476,7 +1477,7 @@ state->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ + spin_lock_irqsave( &info->irq_spinlock, flags); /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq @@ -1484,41 +1485,6 @@ */ wake_up_interruptible(&info->delta_msr_wait); - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[state->irq] = info->next_port; - figure_IRQ_timeout(state->irq); - - /* - * Free the IRQ, if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - free_irq(state->irq, &IRQ_ports[state->irq]); - retval = request_irq(state->irq, rs_interrupt_single, - SA_SHIRQ, "serial", - &IRQ_ports[state->irq]); - - if (retval) - printk("serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(state->irq, &IRQ_ports[state->irq]); - } - - if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = 0; - free_page(pg); - } - info->IER = 0; serial_outp(info, UART_IER, 0x00); /* disable all intrs */ #ifdef CONFIG_SERIAL_MANY_PORTS @@ -1575,7 +1541,43 @@ serial_outp(info, UART_IER, UART_IERX_SLEEP); } info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, &IRQ_ports[state->irq]); + retval = request_irq(state->irq, rs_interrupt_single, + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, &IRQ_ports[state->irq]); + } + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); + } + + spin_unlock_irqrestore( &info->irq_spinlock, flags); } #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ @@ -3095,36 +3097,53 @@ sstate = rs_table + line; sstate->count++; - if (sstate->info) { - *ret_info = sstate->info; - return 0; - } + info = sstate->info; + + /* + * If the async_struct is already allocated, do the fastpath. + */ + if (info) + goto out; + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); if (!info) { sstate->count--; return -ENOMEM; } + memset(info, 0, sizeof(struct async_struct)); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); info->magic = SERIAL_MAGIC; info->port = sstate->port; + info->hub6 = sstate->hub6; info->flags = sstate->flags; - info->io_type = sstate->io_type; - info->iomem_base = sstate->iomem_base; - info->iomem_reg_shift = sstate->iomem_reg_shift; info->xmit_fifo_size = sstate->xmit_fifo_size; + info->state = sstate; info->line = line; + info->iomem_base = sstate->iomem_base; + info->iomem_reg_shift = sstate->iomem_reg_shift; + info->io_type = sstate->io_type; info->tqueue.routine = do_softint; info->tqueue.data = info; - info->state = sstate; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; + if (sstate->info) { kfree(info); - *ret_info = sstate->info; - return 0; + info = sstate->info; + } else { + sstate->info = info; + } + +out: + /* + * If this is the first open, copy over some timeouts. + */ + if (sstate->count == 1) { + info->closing_wait = sstate->closing_wait; } - *ret_info = sstate->info = info; + *ret_info = info; return 0; } @@ -3643,6 +3662,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; save_flags(flags); cli(); @@ -5618,6 +5638,7 @@ info->io_type = req->io_type; info->iomem_base = req->iomem_base; info->iomem_reg_shift = req->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; } autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -5954,6 +5975,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); #if defined(__powerpc__) || defined(__alpha__) diff -urN linux-2.4.17/include/linux/serialP.h linux-2.4.17-serial/include/linux/serialP.h --- linux-2.4.17/include/linux/serialP.h Mon Dec 24 19:45:37 2001 +++ linux-2.4.17-serial/include/linux/serialP.h Sun Jan 6 23:43:13 2002 @@ -70,7 +70,7 @@ int x_char; /* xon/xoff character */ int close_delay; unsigned short closing_wait; - unsigned short closing_wait2; + unsigned short closing_wait2; /* obsolete */ int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ int LCR; /* Line control register */ @@ -83,6 +83,7 @@ long pgrp; /* pgrp of opening process */ struct circ_buf xmit; spinlock_t xmit_lock; + spinlock_t irq_spinlock; u8 *iomem_base; u16 iomem_reg_shift; int io_type;