From: Patrick van de Lageweg This patch converts all save_flags/restore_flags to the new spin_lock_irqsave/spin_unlock_irqrestore calls, as well as some other 2.6.X cleanups. This prepares the way for the "io8+", "sx" and "rio" drivers to become SMP safe. Patches for those drivers follow. Signed-off-by: Patrick vd Lageweg Signed-off-by: Rogier Wolff Signed-off-by: Andrew Morton --- 25-akpm/drivers/char/generic_serial.c | 115 ++++++++++++++++++--------------- 25-akpm/include/linux/generic_serial.h | 4 - 2 files changed, 68 insertions(+), 51 deletions(-) diff -puN drivers/char/generic_serial.c~generic-serial-cli-conversion drivers/char/generic_serial.c --- 25/drivers/char/generic_serial.c~generic-serial-cli-conversion 2005-01-10 21:15:26.119482816 -0800 +++ 25-akpm/drivers/char/generic_serial.c 2005-01-10 21:15:26.126481752 -0800 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -45,8 +46,8 @@ static int gs_debug; #define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__) #define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__) - -#ifdef NEW_WRITE_LOCKING +#define NEW_WRITE_LOCKING 1 +#if NEW_WRITE_LOCKING #define DECL /* Nothing */ #define LOCKIT down (& port->port_write_sem); #define RELEASEIT up (&port->port_write_sem); @@ -208,7 +209,7 @@ int gs_write(struct tty_struct * tty, if (!port || !port->xmit_buf || !tmp_buf) return -EIO; - save_flags(flags); + local_save_flags(flags); while (1) { cli(); c = count; @@ -227,14 +228,14 @@ int gs_write(struct tty_struct * tty, /* Can't copy more? break out! */ if (c <= 0) { - restore_flags(flags); + local_restore_flags(flags); break; } memcpy(port->xmit_buf + port->xmit_head, buf, c); port->xmit_head = ((port->xmit_head + c) & (SERIAL_XMIT_SIZE-1)); port->xmit_cnt += c; - restore_flags(flags); + local_restore_flags(flags); buf += c; count -= c; total += c; @@ -380,9 +381,9 @@ void gs_flush_buffer(struct tty_struct * if (!port) return; /* XXX Would the write semaphore do? */ - save_flags(flags); cli(); + spin_lock_irqsave (&port->driver_lock, flags); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - restore_flags(flags); + spin_unlock_irqrestore (&port->driver_lock, flags); wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); @@ -468,8 +469,7 @@ static void gs_shutdown_port (struct gs_ if (!(port->flags & ASYNC_INITIALIZED)) return; - save_flags (flags); - cli (); + spin_lock_irqsave(&port->driver_lock, flags); if (port->xmit_buf) { free_page((unsigned long) port->xmit_buf); @@ -482,7 +482,7 @@ static void gs_shutdown_port (struct gs_ port->rd->shutdown_port (port); port->flags &= ~ASYNC_INITIALIZED; - restore_flags (flags); + spin_unlock_irqrestore(&port->driver_lock, flags); func_exit(); } @@ -519,6 +519,7 @@ int gs_block_til_ready(void *port_, stru int do_clocal = 0; int CD; struct tty_struct *tty; + unsigned long flags; func_enter (); @@ -570,10 +571,11 @@ int gs_block_til_ready(void *port_, stru add_wait_queue(&port->open_wait, &wait); gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); - cli(); - if (!tty_hung_up_p(filp)) + spin_lock_irqsave(&port->driver_lock, flags); + if (!tty_hung_up_p(filp)) { port->count--; - sti(); + } + spin_unlock_irqrestore(&port->driver_lock, flags); port->blocked_open++; while (1) { CD = port->rd->get_CD (port); @@ -602,8 +604,9 @@ int gs_block_til_ready(void *port_, stru port->blocked_open); set_current_state (TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); - if (!tty_hung_up_p(filp)) + if (!tty_hung_up_p(filp)) { port->count++; + } port->blocked_open--; if (retval) return retval; @@ -633,27 +636,29 @@ void gs_close(struct tty_struct * tty, s port->tty = tty; } - save_flags(flags); cli(); + spin_lock_irqsave(&port->driver_lock, flags); if (tty_hung_up_p(filp)) { - restore_flags(flags); - port->rd->hungup (port); + spin_unlock_irqrestore(&port->driver_lock, flags); + if (port->rd->hungup) + port->rd->hungup (port); func_exit (); return; } if ((tty->count == 1) && (port->count != 1)) { - printk(KERN_ERR "gs: gs_close: bad port count;" - " tty->count is 1, port count is %d\n", port->count); + printk(KERN_ERR "gs: gs_close port %p: bad port count;" + " tty->count is 1, port count is %d\n", port, port->count); port->count = 1; } if (--port->count < 0) { - printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count); + printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->count); port->count = 0; } + if (port->count) { - gs_dprintk(GS_DEBUG_CLOSE, "gs_close: count: %d\n", port->count); - restore_flags(flags); + gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->count); + spin_unlock_irqrestore(&port->driver_lock, flags); func_exit (); return; } @@ -675,16 +680,17 @@ void gs_close(struct tty_struct * tty, s */ port->rd->disable_rx_interrupts (port); + spin_unlock_irqrestore(&port->driver_lock, flags); /* close has no way of returning "EINTR", so discard return value */ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - gs_wait_tx_flushed (port, port->closing_wait); + gs_wait_tx_flushed (port, port->closing_wait); port->flags &= ~GS_ACTIVE; if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - + tty_ldisc_flush(tty); tty->closing = 0; @@ -695,14 +701,15 @@ void gs_close(struct tty_struct * tty, s if (port->blocked_open) { if (port->close_delay) { + spin_unlock_irqrestore(&port->driver_lock, flags); msleep_interruptible(jiffies_to_msecs(port->close_delay)); + spin_lock_irqsave(&port->driver_lock, flags); } wake_up_interruptible(&port->open_wait); } port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED); wake_up_interruptible(&port->close_wait); - restore_flags(flags); func_exit (); } @@ -727,6 +734,12 @@ void gs_set_termios (struct tty_struct * port = tty->driver_data; if (!port) return; + if (!port->tty) { + /* This seems to happen when this is called after gs_close. */ + gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->tty is NULL\n"); + port->tty = tty; + } + tiosp = tty->termios; @@ -821,7 +834,7 @@ void gs_set_termios (struct tty_struct * if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&port->gs.open_wait); #endif func_exit(); @@ -836,56 +849,56 @@ int gs_init_port(struct gs_port *port) unsigned long flags; unsigned long page; - save_flags (flags); - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); + func_enter (); - cli (); /* Don't expect this to make a difference. */ + if (!tmp_buf) { + page = get_zeroed_page(GFP_KERNEL); + spin_lock_irqsave (&port->driver_lock, flags); /* Don't expect this to make a difference. */ if (tmp_buf) free_page(page); else tmp_buf = (unsigned char *) page; - restore_flags (flags); - + spin_unlock_irqrestore (&port->driver_lock, flags); if (!tmp_buf) { + func_exit (); return -ENOMEM; } } - if (port->flags & ASYNC_INITIALIZED) + if (port->flags & ASYNC_INITIALIZED) { + func_exit (); return 0; - + } if (!port->xmit_buf) { /* We may sleep in get_zeroed_page() */ unsigned long tmp; tmp = get_zeroed_page(GFP_KERNEL); - - /* Spinlock? */ - cli (); + spin_lock_irqsave (&port->driver_lock, flags); if (port->xmit_buf) free_page (tmp); else port->xmit_buf = (unsigned char *) tmp; - restore_flags (flags); - - if (!port->xmit_buf) + spin_unlock_irqrestore(&port->driver_lock, flags); + if (!port->xmit_buf) { + func_exit (); return -ENOMEM; + } } - cli(); - + spin_lock_irqsave (&port->driver_lock, flags); if (port->tty) clear_bit(TTY_IO_ERROR, &port->tty->flags); - + init_MUTEX(&port->port_write_sem); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - + spin_unlock_irqrestore(&port->driver_lock, flags); gs_set_termios(port->tty, NULL); - + spin_lock_irqsave (&port->driver_lock, flags); port->flags |= ASYNC_INITIALIZED; port->flags &= ~GS_TX_INTEN; - restore_flags(flags); + spin_unlock_irqrestore(&port->driver_lock, flags); + func_exit (); return 0; } @@ -956,13 +969,15 @@ int gs_getserial(struct gs_port *port, s void gs_got_break(struct gs_port *port) { + func_enter (); + + tty_insert_flip_char(port->tty, 0, TTY_BREAK); + tty_schedule_flip(port->tty); if (port->flags & ASYNC_SAK) { do_SAK (port->tty); } - *(port->tty->flip.flag_buf_ptr) = TTY_BREAK; - port->tty->flip.flag_buf_ptr++; - port->tty->flip.char_buf_ptr++; - port->tty->flip.count++; + + func_exit (); } diff -puN include/linux/generic_serial.h~generic-serial-cli-conversion include/linux/generic_serial.h --- 25/include/linux/generic_serial.h~generic-serial-cli-conversion 2005-01-10 21:15:26.120482664 -0800 +++ 25-akpm/include/linux/generic_serial.h 2005-01-10 21:15:26.127481600 -0800 @@ -34,7 +34,7 @@ struct gs_port { int xmit_head; int xmit_tail; int xmit_cnt; - /* struct semaphore port_write_sem; */ + struct semaphore port_write_sem; int flags; wait_queue_head_t open_wait; wait_queue_head_t close_wait; @@ -49,6 +49,7 @@ struct gs_port { int baud_base; int baud; int custom_divisor; + spinlock_t driver_lock; }; @@ -70,6 +71,7 @@ struct gs_port { #define GS_DEBUG_STUFF 0x00000008 #define GS_DEBUG_CLOSE 0x00000010 #define GS_DEBUG_FLOW 0x00000020 +#define GS_DEBUG_WRITE 0x00000040 void gs_put_char(struct tty_struct *tty, unsigned char ch); _