| 1 | --- a/nozomi.c |
| 2 | +++ b/nozomi.c |
| 3 | @@ -7,6 +7,9 @@ |
| 4 | * |
| 5 | * Maintained by: Paul Hardwick, p.hardwick@option.com |
| 6 | * |
| 7 | + * Patches: |
| 8 | + * Locking code changes for Vodafone, Andrew Bird & Phil Sanderson |
| 9 | + * |
| 10 | * Source has been ported from an implementation made by Filip Aben, f.aben@option.com |
| 11 | * |
| 12 | * -------------------------------------------------------------------------- |
| 13 | @@ -61,6 +64,7 @@ |
| 14 | #include <linux/interrupt.h> |
| 15 | #include <linux/kmod.h> |
| 16 | #include <linux/proc_fs.h> |
| 17 | +#include <linux/init.h> |
| 18 | #include <asm/uaccess.h> |
| 19 | |
| 20 | |
| 21 | @@ -133,23 +137,23 @@ static int nzdebug = NOZOMI_DEBUG_LEVEL; |
| 22 | /* TODO: rewrite to optimize macros... */ |
| 23 | #define SET_FCR(value__) \ |
| 24 | do { \ |
| 25 | - writew((value__), (void*) (dc->REG_FCR )); \ |
| 26 | + writew((value__), (dc->REG_FCR )); \ |
| 27 | } while(0) |
| 28 | |
| 29 | #define SET_IER(value__, mask__) \ |
| 30 | do { \ |
| 31 | dc->ier_last_written = (dc->ier_last_written & ~mask__) | (value__ & mask__ );\ |
| 32 | - writew( dc->ier_last_written, (void*) (dc->REG_IER));\ |
| 33 | + writew( dc->ier_last_written, (dc->REG_IER));\ |
| 34 | } while(0) |
| 35 | |
| 36 | #define GET_IER(read_val__) \ |
| 37 | do { \ |
| 38 | - (read_val__) = readw((void*) (dc->REG_IER));\ |
| 39 | + (read_val__) = readw((dc->REG_IER));\ |
| 40 | } while(0) |
| 41 | |
| 42 | #define GET_IIR(read_val__) \ |
| 43 | do { \ |
| 44 | - (read_val__) = readw((void*) (dc->REG_IIR));\ |
| 45 | + (read_val__) = readw( (dc->REG_IIR));\ |
| 46 | } while(0) |
| 47 | |
| 48 | #define GET_MEM(value__, addr__, length__) \ |
| 49 | @@ -265,7 +269,7 @@ static int nzdebug = NOZOMI_DEBUG_LEVEL; |
| 50 | /* There are two types of nozomi cards, one with 2048 memory and with 8192 memory */ |
| 51 | typedef enum { |
| 52 | F32_2 = 2048, /* Has 512 bytes downlink and uplink * 2 -> 2048 */ |
| 53 | - F32_8 = 9192, /* Has 3072 bytes downlink and 1024 bytes uplink * 2 -> 8192 */ |
| 54 | + F32_8 = 8192, /* Has 3072 bytes downlink and 1024 bytes uplink * 2 -> 8192 */ |
| 55 | } card_type_t; |
| 56 | |
| 57 | /* Two different toggle channels exist */ |
| 58 | @@ -438,12 +442,12 @@ typedef struct { |
| 59 | u32 base_addr; |
| 60 | u8 closing; |
| 61 | |
| 62 | - /* Register addresses */ |
| 63 | - u32 REG_IIR; |
| 64 | - u32 REG_FCR; |
| 65 | - u32 REG_IER; |
| 66 | + /* Pointers to registers ( register is tagged volatile, not pointer ) */ |
| 67 | + volatile u16 * REG_IIR; |
| 68 | + volatile u16 * REG_FCR; |
| 69 | + volatile u16 * REG_IER; |
| 70 | |
| 71 | - volatile u16 ier_last_written; |
| 72 | + u16 ier_last_written; |
| 73 | card_type_t card_type; |
| 74 | config_table_t config_table; /* Configuration table */ |
| 75 | struct pci_dev *pdev; |
| 76 | @@ -490,7 +494,7 @@ static struct pci_device_id nozomi_pci_t |
| 77 | |
| 78 | /* Used to store interrupt variables */ |
| 79 | typedef struct { |
| 80 | - volatile u16 read_iir; /* Holds current interrupt tokens */ |
| 81 | + u16 read_iir; /* Holds current interrupt tokens */ |
| 82 | } irq_t; |
| 83 | |
| 84 | MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); |
| 85 | @@ -1345,9 +1349,9 @@ void nozomi_setup_private_data(dc_t *dc) |
| 86 | u32 offset = dc->base_addr + dc->card_type/2; |
| 87 | int i; |
| 88 | |
| 89 | - dc->REG_FCR = offset + R_FCR; |
| 90 | - dc->REG_IIR = offset + R_IIR; |
| 91 | - dc->REG_IER = offset + R_IER; |
| 92 | + dc->REG_FCR = (u16 *) (offset + R_FCR); |
| 93 | + dc->REG_IIR = (u16 *) (offset + R_IIR); |
| 94 | + dc->REG_IER = (u16 *) (offset + R_IER); |
| 95 | dc->ier_last_written = 0; |
| 96 | dc->closing = 0; |
| 97 | |
| 98 | @@ -1366,13 +1370,16 @@ void nozomi_setup_private_data(dc_t *dc) |
| 99 | static void tty_flip_queue_function(void *tmp_dc) { |
| 100 | dc_t *dc = (dc_t*) tmp_dc; |
| 101 | int i; |
| 102 | + u32 flags; |
| 103 | |
| 104 | /* Enable interrupt for that port */ |
| 105 | for(i=0;i<MAX_PORT;i++) { |
| 106 | if (dc->port[i].tty_dont_flip) { |
| 107 | D6("Enable for port: %d", i); |
| 108 | dc->port[i].tty_dont_flip = 0; |
| 109 | + spin_lock_irqsave(&dc->spin_mutex, flags); |
| 110 | enable_transmit_dl(dc->port[i].tty_index, dc); |
| 111 | + spin_unlock_irqrestore(&dc->spin_mutex, flags); |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | @@ -1555,7 +1562,11 @@ err_disable_device: |
| 116 | |
| 117 | static void tty_do_close(dc_t *dc, port_t *port) { |
| 118 | |
| 119 | - down(&port->tty_sem); |
| 120 | + u32 flags; |
| 121 | + |
| 122 | + if(down_interruptible(&port->tty_sem)){ |
| 123 | + return; |
| 124 | + } |
| 125 | |
| 126 | if ( !port->tty_open_count ) { |
| 127 | goto exit; |
| 128 | @@ -1569,7 +1580,9 @@ static void tty_do_close(dc_t *dc, port_ |
| 129 | |
| 130 | if ( port->tty_open_count == 0) { |
| 131 | D1("close: %d", port->token_dl ); |
| 132 | + spin_lock_irqsave(&dc->spin_mutex, flags); |
| 133 | SET_IER( 0, port->token_dl ); |
| 134 | + spin_unlock_irqrestore(&dc->spin_mutex, flags); |
| 135 | } |
| 136 | |
| 137 | exit: |
| 138 | @@ -1679,8 +1692,11 @@ static int ntty_open(struct tty_struct * |
| 139 | s32 index = get_index(tty); |
| 140 | port_t *port = get_port_by_tty(tty); |
| 141 | dc_t *dc = get_dc_by_tty(tty); |
| 142 | + u32 flags; |
| 143 | |
| 144 | - down(&port->tty_sem); |
| 145 | + if(down_interruptible(&port->tty_sem)){ |
| 146 | + return -ERESTARTSYS; |
| 147 | + } |
| 148 | |
| 149 | tty->low_latency = 1; |
| 150 | tty->driver_data = port; |
| 151 | @@ -1698,7 +1714,9 @@ static int ntty_open(struct tty_struct * |
| 152 | if ( port->tty_open_count == 1) { |
| 153 | port->rx_data = port->tx_data = 0; |
| 154 | D1("open: %d", port->token_dl ); |
| 155 | + spin_lock_irqsave(&dc->spin_mutex, flags); |
| 156 | SET_IER( port->token_dl, port->token_dl ); |
| 157 | + spin_unlock_irqrestore(&dc->spin_mutex, flags); |
| 158 | } |
| 159 | |
| 160 | up(&port->tty_sem); |
| 161 | @@ -1722,6 +1740,7 @@ static s32 ntty_write(struct tty_struct |
| 162 | int rval = -EINVAL; |
| 163 | dc_t *dc = get_dc_by_tty(tty); |
| 164 | port_t *port = (port_t *) tty->driver_data; |
| 165 | + u32 flags; |
| 166 | |
| 167 | /* D1( "WRITEx: %d, index = %d", count, index); */ |
| 168 | |
| 169 | @@ -1729,7 +1748,10 @@ static s32 ntty_write(struct tty_struct |
| 170 | return -ENODEV; |
| 171 | } |
| 172 | |
| 173 | - down(&port->tty_sem); |
| 174 | + if(down_trylock(&port->tty_sem) ) { // must test lock as tty layer wraps calls to this function with BKL |
| 175 | + ERR("Would have deadlocked - return ERESTARTSYS"); |
| 176 | + return -ERESTARTSYS; |
| 177 | + } |
| 178 | |
| 179 | if (! port->tty_open_count) { |
| 180 | D1( " "); |
| 181 | @@ -1752,6 +1774,7 @@ static s32 ntty_write(struct tty_struct |
| 182 | goto exit; |
| 183 | } |
| 184 | |
| 185 | + spin_lock_irqsave(&dc->spin_mutex, flags); |
| 186 | // CTS is only valid on the modem channel |
| 187 | if ( port == &(dc->port[PORT_MDM]) ) { |
| 188 | if ( port->ctrl_dl.CTS ) { |
| 189 | @@ -1763,6 +1786,7 @@ static s32 ntty_write(struct tty_struct |
| 190 | } else { |
| 191 | enable_transmit_ul(port->tty_index, dc ); |
| 192 | } |
| 193 | + spin_unlock_irqrestore(&dc->spin_mutex, flags); |
| 194 | |
| 195 | exit: |
| 196 | up(&port->tty_sem); |
| 197 | @@ -1782,7 +1806,9 @@ static int ntty_write_room(struct tty_st |
| 198 | return 0; |
| 199 | } |
| 200 | |
| 201 | - down(&port->tty_sem); |
| 202 | + if(down_interruptible(&port->tty_sem)){ |
| 203 | + return 0; |
| 204 | + } |
| 205 | |
| 206 | if (! port->tty_open_count) { |
| 207 | goto exit; |
| 208 | @@ -1969,6 +1995,8 @@ static int ntty_ioctl_tiocgicount(struct |
| 209 | |
| 210 | static int ntty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { |
| 211 | port_t *port = (port_t *) tty->driver_data; |
| 212 | + dc_t *dc = get_dc_by_tty(tty); |
| 213 | + u32 flags; |
| 214 | int mask; |
| 215 | int rval = -ENOIOCTLCMD; |
| 216 | |
| 217 | @@ -1991,7 +2019,9 @@ static int ntty_ioctl(struct tty_struct |
| 218 | rval = ntty_ioctl_tiocgicount(tty, file, cmd, arg); |
| 219 | break; |
| 220 | case TIOCMGET: |
| 221 | + spin_lock_irqsave(&dc->spin_mutex, flags); |
| 222 | rval = ntty_tiocmget(tty, file); |
| 223 | + spin_unlock_irqrestore(&dc->spin_mutex, flags); |
| 224 | break; |
| 225 | case TIOCMSET: |
| 226 | rval = ntty_tiocmset(tty, file, arg); |
| 227 | @@ -2000,20 +2030,24 @@ static int ntty_ioctl(struct tty_struct |
| 228 | if (get_user(mask, (unsigned long *) arg)) |
| 229 | return -EFAULT; |
| 230 | |
| 231 | + spin_lock_irqsave(&dc->spin_mutex, flags); |
| 232 | if (mask & TIOCM_RTS) |
| 233 | set_rts(port->tty_index, 0); |
| 234 | if (mask & TIOCM_DTR) |
| 235 | set_dtr(port->tty_index, 0); |
| 236 | + spin_unlock_irqrestore(&dc->spin_mutex, flags); |
| 237 | rval = 0; |
| 238 | break; |
| 239 | case TIOCMBIS: |
| 240 | if (get_user(mask, (unsigned long *) arg)) |
| 241 | return -EFAULT; |
| 242 | |
| 243 | + spin_lock_irqsave(&dc->spin_mutex, flags); |
| 244 | if (mask & TIOCM_RTS) |
| 245 | set_rts(port->tty_index, 1); |
| 246 | if (mask & TIOCM_DTR) |
| 247 | set_dtr(port->tty_index, 1); |
| 248 | + spin_unlock_irqrestore(&dc->spin_mutex, flags); |
| 249 | rval = 0; |
| 250 | break; |
| 251 | case TCFLSH: |
| 252 | |