--- nozomi/nozomi.c.orig 2006-04-16 12:15:42.000000000 +0100 +++ nozomi/nozomi.c 2006-04-19 18:27:29.000000000 +0100 @@ -7,6 +7,9 @@ * * Maintained by: Paul Hardwick, p.hardwick@option.com * + * Patches: + * Locking code changes for Vodafone, Andrew Bird & Phil Sanderson + * * Source has been ported from an implementation made by Filip Aben, f.aben@option.com * * -------------------------------------------------------------------------- @@ -61,6 +64,7 @@ #include #include #include +#include #include @@ -133,23 +137,23 @@ /* TODO: rewrite to optimize macros... */ #define SET_FCR(value__) \ do { \ - writew((value__), (void*) (dc->REG_FCR )); \ + writew((value__), (dc->REG_FCR )); \ } while(0) #define SET_IER(value__, mask__) \ do { \ dc->ier_last_written = (dc->ier_last_written & ~mask__) | (value__ & mask__ );\ - writew( dc->ier_last_written, (void*) (dc->REG_IER));\ + writew( dc->ier_last_written, (dc->REG_IER));\ } while(0) #define GET_IER(read_val__) \ do { \ - (read_val__) = readw((void*) (dc->REG_IER));\ + (read_val__) = readw((dc->REG_IER));\ } while(0) #define GET_IIR(read_val__) \ do { \ - (read_val__) = readw((void*) (dc->REG_IIR));\ + (read_val__) = readw( (dc->REG_IIR));\ } while(0) #define GET_MEM(value__, addr__, length__) \ @@ -265,7 +268,7 @@ /* There are two types of nozomi cards, one with 2048 memory and with 8192 memory */ typedef enum { F32_2 = 2048, /* Has 512 bytes downlink and uplink * 2 -> 2048 */ - F32_8 = 9192, /* Has 3072 bytes downlink and 1024 bytes uplink * 2 -> 8192 */ + F32_8 = 8192, /* Has 3072 bytes downlink and 1024 bytes uplink * 2 -> 8192 */ } card_type_t; /* Two different toggle channels exist */ @@ -438,12 +441,12 @@ u32 base_addr; u8 closing; - /* Register addresses */ - u32 REG_IIR; - u32 REG_FCR; - u32 REG_IER; + /* Pointers to registers ( register is tagged volatile, not pointer ) */ + volatile u16 * REG_IIR; + volatile u16 * REG_FCR; + volatile u16 * REG_IER; - volatile u16 ier_last_written; + u16 ier_last_written; card_type_t card_type; config_table_t config_table; /* Configuration table */ struct pci_dev *pdev; @@ -490,7 +493,7 @@ /* Used to store interrupt variables */ typedef struct { - volatile u16 read_iir; /* Holds current interrupt tokens */ + u16 read_iir; /* Holds current interrupt tokens */ } irq_t; MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); @@ -1345,9 +1348,9 @@ u32 offset = dc->base_addr + dc->card_type/2; int i; - dc->REG_FCR = offset + R_FCR; - dc->REG_IIR = offset + R_IIR; - dc->REG_IER = offset + R_IER; + dc->REG_FCR = (u16 *) (offset + R_FCR); + dc->REG_IIR = (u16 *) (offset + R_IIR); + dc->REG_IER = (u16 *) (offset + R_IER); dc->ier_last_written = 0; dc->closing = 0; @@ -1366,13 +1369,16 @@ static void tty_flip_queue_function(void *tmp_dc) { dc_t *dc = (dc_t*) tmp_dc; int i; + u32 flags; /* Enable interrupt for that port */ for(i=0;iport[i].tty_dont_flip) { D6("Enable for port: %d", i); dc->port[i].tty_dont_flip = 0; + spin_lock_irqsave(&dc->spin_mutex, flags); enable_transmit_dl(dc->port[i].tty_index, dc); + spin_unlock_irqrestore(&dc->spin_mutex, flags); } } } @@ -1555,7 +1561,11 @@ static void tty_do_close(dc_t *dc, port_t *port) { - down(&port->tty_sem); + u32 flags; + + if(down_interruptible(&port->tty_sem)){ + return; + } if ( !port->tty_open_count ) { goto exit; @@ -1569,7 +1579,9 @@ if ( port->tty_open_count == 0) { D1("close: %d", port->token_dl ); + spin_lock_irqsave(&dc->spin_mutex, flags); SET_IER( 0, port->token_dl ); + spin_unlock_irqrestore(&dc->spin_mutex, flags); } exit: @@ -1679,8 +1691,11 @@ s32 index = get_index(tty); port_t *port = get_port_by_tty(tty); dc_t *dc = get_dc_by_tty(tty); + u32 flags; - down(&port->tty_sem); + if(down_interruptible(&port->tty_sem)){ + return -ERESTARTSYS; + } tty->low_latency = 1; tty->driver_data = port; @@ -1698,7 +1713,9 @@ if ( port->tty_open_count == 1) { port->rx_data = port->tx_data = 0; D1("open: %d", port->token_dl ); + spin_lock_irqsave(&dc->spin_mutex, flags); SET_IER( port->token_dl, port->token_dl ); + spin_unlock_irqrestore(&dc->spin_mutex, flags); } up(&port->tty_sem); @@ -1722,6 +1739,7 @@ int rval = -EINVAL; dc_t *dc = get_dc_by_tty(tty); port_t *port = (port_t *) tty->driver_data; + u32 flags; /* D1( "WRITEx: %d, index = %d", count, index); */ @@ -1729,7 +1747,10 @@ return -ENODEV; } - down(&port->tty_sem); + if(down_trylock(&port->tty_sem) ) { // must test lock as tty layer wraps calls to this function with BKL + ERR("Would have deadlocked - return ERESTARTSYS"); + return -ERESTARTSYS; + } if (! port->tty_open_count) { D1( " "); @@ -1752,6 +1773,7 @@ goto exit; } + spin_lock_irqsave(&dc->spin_mutex, flags); // CTS is only valid on the modem channel if ( port == &(dc->port[PORT_MDM]) ) { if ( port->ctrl_dl.CTS ) { @@ -1763,6 +1785,7 @@ } else { enable_transmit_ul(port->tty_index, dc ); } + spin_unlock_irqrestore(&dc->spin_mutex, flags); exit: up(&port->tty_sem); @@ -1782,7 +1805,9 @@ return 0; } - down(&port->tty_sem); + if(down_interruptible(&port->tty_sem)){ + return 0; + } if (! port->tty_open_count) { goto exit; @@ -1969,6 +1994,8 @@ static int ntty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { port_t *port = (port_t *) tty->driver_data; + dc_t *dc = get_dc_by_tty(tty); + u32 flags; int mask; int rval = -ENOIOCTLCMD; @@ -1991,7 +2018,9 @@ rval = ntty_ioctl_tiocgicount(tty, file, cmd, arg); break; case TIOCMGET: + spin_lock_irqsave(&dc->spin_mutex, flags); rval = ntty_tiocmget(tty, file); + spin_unlock_irqrestore(&dc->spin_mutex, flags); break; case TIOCMSET: rval = ntty_tiocmset(tty, file, arg); @@ -2000,20 +2029,24 @@ if (get_user(mask, (unsigned long *) arg)) return -EFAULT; + spin_lock_irqsave(&dc->spin_mutex, flags); if (mask & TIOCM_RTS) set_rts(port->tty_index, 0); if (mask & TIOCM_DTR) set_dtr(port->tty_index, 0); + spin_unlock_irqrestore(&dc->spin_mutex, flags); rval = 0; break; case TIOCMBIS: if (get_user(mask, (unsigned long *) arg)) return -EFAULT; + spin_lock_irqsave(&dc->spin_mutex, flags); if (mask & TIOCM_RTS) set_rts(port->tty_index, 1); if (mask & TIOCM_DTR) set_dtr(port->tty_index, 1); + spin_unlock_irqrestore(&dc->spin_mutex, flags); rval = 0; break; case TCFLSH: