diff options
Diffstat (limited to 'drivers/net/ethernet/3com/3c589_cs.c')
-rw-r--r-- | drivers/net/ethernet/3com/3c589_cs.c | 1127 |
1 files changed, 584 insertions, 543 deletions
diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c index 5992860a39c9..063557e037f2 100644 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ b/drivers/net/ethernet/3com/3c589_cs.c | |||
@@ -1,23 +1,24 @@ | |||
1 | /*====================================================================== | 1 | /* ====================================================================== |
2 | 2 | * | |
3 | A PCMCIA ethernet driver for the 3com 3c589 card. | 3 | * A PCMCIA ethernet driver for the 3com 3c589 card. |
4 | 4 | * | |
5 | Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net | 5 | * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net |
6 | 6 | * | |
7 | 3c589_cs.c 1.162 2001/10/13 00:08:50 | 7 | * 3c589_cs.c 1.162 2001/10/13 00:08:50 |
8 | 8 | * | |
9 | The network driver code is based on Donald Becker's 3c589 code: | 9 | * The network driver code is based on Donald Becker's 3c589 code: |
10 | 10 | * | |
11 | Written 1994 by Donald Becker. | 11 | * Written 1994 by Donald Becker. |
12 | Copyright 1993 United States Government as represented by the | 12 | * Copyright 1993 United States Government as represented by the |
13 | Director, National Security Agency. This software may be used and | 13 | * Director, National Security Agency. This software may be used and |
14 | distributed according to the terms of the GNU General Public License, | 14 | * distributed according to the terms of the GNU General Public License, |
15 | incorporated herein by reference. | 15 | * incorporated herein by reference. |
16 | Donald Becker may be reached at becker@scyld.com | 16 | * Donald Becker may be reached at becker@scyld.com |
17 | 17 | * | |
18 | Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> | 18 | * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> |
19 | 19 | * | |
20 | ======================================================================*/ | 20 | * ====================================================================== |
21 | */ | ||
21 | 22 | ||
22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
23 | 24 | ||
@@ -41,18 +42,20 @@ | |||
41 | #include <linux/ioport.h> | 42 | #include <linux/ioport.h> |
42 | #include <linux/bitops.h> | 43 | #include <linux/bitops.h> |
43 | #include <linux/jiffies.h> | 44 | #include <linux/jiffies.h> |
45 | #include <linux/uaccess.h> | ||
46 | #include <linux/io.h> | ||
44 | 47 | ||
45 | #include <pcmcia/cistpl.h> | 48 | #include <pcmcia/cistpl.h> |
46 | #include <pcmcia/cisreg.h> | 49 | #include <pcmcia/cisreg.h> |
47 | #include <pcmcia/ciscode.h> | 50 | #include <pcmcia/ciscode.h> |
48 | #include <pcmcia/ds.h> | 51 | #include <pcmcia/ds.h> |
49 | 52 | ||
50 | #include <asm/uaccess.h> | ||
51 | #include <asm/io.h> | ||
52 | 53 | ||
53 | /* To minimize the size of the driver source I only define operating | 54 | /* To minimize the size of the driver source I only define operating |
54 | constants if they are used several times. You'll need the manual | 55 | * constants if they are used several times. You'll need the manual |
55 | if you want to understand driver details. */ | 56 | * if you want to understand driver details. |
57 | */ | ||
58 | |||
56 | /* Offsets from base I/O address. */ | 59 | /* Offsets from base I/O address. */ |
57 | #define EL3_DATA 0x00 | 60 | #define EL3_DATA 0x00 |
58 | #define EL3_TIMER 0x0a | 61 | #define EL3_TIMER 0x0a |
@@ -65,7 +68,9 @@ | |||
65 | #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) | 68 | #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) |
66 | 69 | ||
67 | /* The top five bits written to EL3_CMD are a command, the lower | 70 | /* The top five bits written to EL3_CMD are a command, the lower |
68 | 11 bits are the parameter, if applicable. */ | 71 | * 11 bits are the parameter, if applicable. |
72 | */ | ||
73 | |||
69 | enum c509cmd { | 74 | enum c509cmd { |
70 | TotalReset = 0<<11, | 75 | TotalReset = 0<<11, |
71 | SelectWindow = 1<<11, | 76 | SelectWindow = 1<<11, |
@@ -190,138 +195,142 @@ static const struct net_device_ops el3_netdev_ops = { | |||
190 | 195 | ||
191 | static int tc589_probe(struct pcmcia_device *link) | 196 | static int tc589_probe(struct pcmcia_device *link) |
192 | { | 197 | { |
193 | struct el3_private *lp; | 198 | struct el3_private *lp; |
194 | struct net_device *dev; | 199 | struct net_device *dev; |
195 | 200 | ||
196 | dev_dbg(&link->dev, "3c589_attach()\n"); | 201 | dev_dbg(&link->dev, "3c589_attach()\n"); |
197 | 202 | ||
198 | /* Create new ethernet device */ | 203 | /* Create new ethernet device */ |
199 | dev = alloc_etherdev(sizeof(struct el3_private)); | 204 | dev = alloc_etherdev(sizeof(struct el3_private)); |
200 | if (!dev) | 205 | if (!dev) |
201 | return -ENOMEM; | 206 | return -ENOMEM; |
202 | lp = netdev_priv(dev); | 207 | lp = netdev_priv(dev); |
203 | link->priv = dev; | 208 | link->priv = dev; |
204 | lp->p_dev = link; | 209 | lp->p_dev = link; |
205 | 210 | ||
206 | spin_lock_init(&lp->lock); | 211 | spin_lock_init(&lp->lock); |
207 | link->resource[0]->end = 16; | 212 | link->resource[0]->end = 16; |
208 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; | 213 | link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; |
209 | 214 | ||
210 | link->config_flags |= CONF_ENABLE_IRQ; | 215 | link->config_flags |= CONF_ENABLE_IRQ; |
211 | link->config_index = 1; | 216 | link->config_index = 1; |
212 | 217 | ||
213 | dev->netdev_ops = &el3_netdev_ops; | 218 | dev->netdev_ops = &el3_netdev_ops; |
214 | dev->watchdog_timeo = TX_TIMEOUT; | 219 | dev->watchdog_timeo = TX_TIMEOUT; |
215 | 220 | ||
216 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | 221 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); |
217 | 222 | ||
218 | return tc589_config(link); | 223 | return tc589_config(link); |
219 | } | 224 | } |
220 | 225 | ||
221 | static void tc589_detach(struct pcmcia_device *link) | 226 | static void tc589_detach(struct pcmcia_device *link) |
222 | { | 227 | { |
223 | struct net_device *dev = link->priv; | 228 | struct net_device *dev = link->priv; |
224 | 229 | ||
225 | dev_dbg(&link->dev, "3c589_detach\n"); | 230 | dev_dbg(&link->dev, "3c589_detach\n"); |
226 | 231 | ||
227 | unregister_netdev(dev); | 232 | unregister_netdev(dev); |
228 | 233 | ||
229 | tc589_release(link); | 234 | tc589_release(link); |
230 | 235 | ||
231 | free_netdev(dev); | 236 | free_netdev(dev); |
232 | } /* tc589_detach */ | 237 | } /* tc589_detach */ |
233 | 238 | ||
234 | static int tc589_config(struct pcmcia_device *link) | 239 | static int tc589_config(struct pcmcia_device *link) |
235 | { | 240 | { |
236 | struct net_device *dev = link->priv; | 241 | struct net_device *dev = link->priv; |
237 | __be16 *phys_addr; | 242 | __be16 *phys_addr; |
238 | int ret, i, j, multi = 0, fifo; | 243 | int ret, i, j, multi = 0, fifo; |
239 | unsigned int ioaddr; | 244 | unsigned int ioaddr; |
240 | static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; | 245 | static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; |
241 | u8 *buf; | 246 | u8 *buf; |
242 | size_t len; | 247 | size_t len; |
243 | 248 | ||
244 | dev_dbg(&link->dev, "3c589_config\n"); | 249 | dev_dbg(&link->dev, "3c589_config\n"); |
245 | 250 | ||
246 | phys_addr = (__be16 *)dev->dev_addr; | 251 | phys_addr = (__be16 *)dev->dev_addr; |
247 | /* Is this a 3c562? */ | 252 | /* Is this a 3c562? */ |
248 | if (link->manf_id != MANFID_3COM) | 253 | if (link->manf_id != MANFID_3COM) |
249 | dev_info(&link->dev, "hmmm, is this really a 3Com card??\n"); | 254 | dev_info(&link->dev, "hmmm, is this really a 3Com card??\n"); |
250 | multi = (link->card_id == PRODID_3COM_3C562); | 255 | multi = (link->card_id == PRODID_3COM_3C562); |
251 | 256 | ||
252 | link->io_lines = 16; | 257 | link->io_lines = 16; |
253 | 258 | ||
254 | /* For the 3c562, the base address must be xx00-xx7f */ | 259 | /* For the 3c562, the base address must be xx00-xx7f */ |
255 | for (i = j = 0; j < 0x400; j += 0x10) { | 260 | for (i = j = 0; j < 0x400; j += 0x10) { |
256 | if (multi && (j & 0x80)) continue; | 261 | if (multi && (j & 0x80)) |
257 | link->resource[0]->start = j ^ 0x300; | 262 | continue; |
258 | i = pcmcia_request_io(link); | 263 | link->resource[0]->start = j ^ 0x300; |
259 | if (i == 0) | 264 | i = pcmcia_request_io(link); |
260 | break; | 265 | if (i == 0) |
261 | } | 266 | break; |
262 | if (i != 0) | ||
263 | goto failed; | ||
264 | |||
265 | ret = pcmcia_request_irq(link, el3_interrupt); | ||
266 | if (ret) | ||
267 | goto failed; | ||
268 | |||
269 | ret = pcmcia_enable_device(link); | ||
270 | if (ret) | ||
271 | goto failed; | ||
272 | |||
273 | dev->irq = link->irq; | ||
274 | dev->base_addr = link->resource[0]->start; | ||
275 | ioaddr = dev->base_addr; | ||
276 | EL3WINDOW(0); | ||
277 | |||
278 | /* The 3c589 has an extra EEPROM for configuration info, including | ||
279 | the hardware address. The 3c562 puts the address in the CIS. */ | ||
280 | len = pcmcia_get_tuple(link, 0x88, &buf); | ||
281 | if (buf && len >= 6) { | ||
282 | for (i = 0; i < 3; i++) | ||
283 | phys_addr[i] = htons(le16_to_cpu(buf[i*2])); | ||
284 | kfree(buf); | ||
285 | } else { | ||
286 | kfree(buf); /* 0 < len < 6 */ | ||
287 | for (i = 0; i < 3; i++) | ||
288 | phys_addr[i] = htons(read_eeprom(ioaddr, i)); | ||
289 | if (phys_addr[0] == htons(0x6060)) { | ||
290 | dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n", | ||
291 | dev->base_addr, dev->base_addr+15); | ||
292 | goto failed; | ||
293 | } | 267 | } |
294 | } | 268 | if (i != 0) |
295 | 269 | goto failed; | |
296 | /* The address and resource configuration register aren't loaded from | 270 | |
297 | the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ | 271 | ret = pcmcia_request_irq(link, el3_interrupt); |
298 | outw(0x3f00, ioaddr + 8); | 272 | if (ret) |
299 | fifo = inl(ioaddr); | 273 | goto failed; |
300 | 274 | ||
301 | /* The if_port symbol can be set when the module is loaded */ | 275 | ret = pcmcia_enable_device(link); |
302 | if ((if_port >= 0) && (if_port <= 3)) | 276 | if (ret) |
303 | dev->if_port = if_port; | 277 | goto failed; |
304 | else | 278 | |
305 | dev_err(&link->dev, "invalid if_port requested\n"); | 279 | dev->irq = link->irq; |
306 | 280 | dev->base_addr = link->resource[0]->start; | |
307 | SET_NETDEV_DEV(dev, &link->dev); | 281 | ioaddr = dev->base_addr; |
308 | 282 | EL3WINDOW(0); | |
309 | if (register_netdev(dev) != 0) { | 283 | |
310 | dev_err(&link->dev, "register_netdev() failed\n"); | 284 | /* The 3c589 has an extra EEPROM for configuration info, including |
311 | goto failed; | 285 | * the hardware address. The 3c562 puts the address in the CIS. |
312 | } | 286 | */ |
313 | 287 | len = pcmcia_get_tuple(link, 0x88, &buf); | |
314 | netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n", | 288 | if (buf && len >= 6) { |
315 | (multi ? "562" : "589"), dev->base_addr, dev->irq, | 289 | for (i = 0; i < 3; i++) |
316 | dev->dev_addr); | 290 | phys_addr[i] = htons(le16_to_cpu(buf[i*2])); |
317 | netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n", | 291 | kfree(buf); |
318 | (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], | 292 | } else { |
319 | if_names[dev->if_port]); | 293 | kfree(buf); /* 0 < len < 6 */ |
320 | return 0; | 294 | for (i = 0; i < 3; i++) |
295 | phys_addr[i] = htons(read_eeprom(ioaddr, i)); | ||
296 | if (phys_addr[0] == htons(0x6060)) { | ||
297 | dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n", | ||
298 | dev->base_addr, dev->base_addr+15); | ||
299 | goto failed; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | /* The address and resource configuration register aren't loaded from | ||
304 | * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. | ||
305 | */ | ||
306 | |||
307 | outw(0x3f00, ioaddr + 8); | ||
308 | fifo = inl(ioaddr); | ||
309 | |||
310 | /* The if_port symbol can be set when the module is loaded */ | ||
311 | if ((if_port >= 0) && (if_port <= 3)) | ||
312 | dev->if_port = if_port; | ||
313 | else | ||
314 | dev_err(&link->dev, "invalid if_port requested\n"); | ||
315 | |||
316 | SET_NETDEV_DEV(dev, &link->dev); | ||
317 | |||
318 | if (register_netdev(dev) != 0) { | ||
319 | dev_err(&link->dev, "register_netdev() failed\n"); | ||
320 | goto failed; | ||
321 | } | ||
322 | |||
323 | netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n", | ||
324 | (multi ? "562" : "589"), dev->base_addr, dev->irq, | ||
325 | dev->dev_addr); | ||
326 | netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n", | ||
327 | (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], | ||
328 | if_names[dev->if_port]); | ||
329 | return 0; | ||
321 | 330 | ||
322 | failed: | 331 | failed: |
323 | tc589_release(link); | 332 | tc589_release(link); |
324 | return -ENODEV; | 333 | return -ENODEV; |
325 | } /* tc589_config */ | 334 | } /* tc589_config */ |
326 | 335 | ||
327 | static void tc589_release(struct pcmcia_device *link) | 336 | static void tc589_release(struct pcmcia_device *link) |
@@ -353,113 +362,120 @@ static int tc589_resume(struct pcmcia_device *link) | |||
353 | 362 | ||
354 | /*====================================================================*/ | 363 | /*====================================================================*/ |
355 | 364 | ||
356 | /* | 365 | /* Use this for commands that may take time to finish */ |
357 | Use this for commands that may take time to finish | 366 | |
358 | */ | ||
359 | static void tc589_wait_for_completion(struct net_device *dev, int cmd) | 367 | static void tc589_wait_for_completion(struct net_device *dev, int cmd) |
360 | { | 368 | { |
361 | int i = 100; | 369 | int i = 100; |
362 | outw(cmd, dev->base_addr + EL3_CMD); | 370 | outw(cmd, dev->base_addr + EL3_CMD); |
363 | while (--i > 0) | 371 | while (--i > 0) |
364 | if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; | 372 | if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) |
365 | if (i == 0) | 373 | break; |
366 | netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); | 374 | if (i == 0) |
375 | netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); | ||
367 | } | 376 | } |
368 | 377 | ||
369 | /* | 378 | /* Read a word from the EEPROM using the regular EEPROM access register. |
370 | Read a word from the EEPROM using the regular EEPROM access register. | 379 | * Assume that we are in register window zero. |
371 | Assume that we are in register window zero. | 380 | */ |
372 | */ | 381 | |
373 | static u16 read_eeprom(unsigned int ioaddr, int index) | 382 | static u16 read_eeprom(unsigned int ioaddr, int index) |
374 | { | 383 | { |
375 | int i; | 384 | int i; |
376 | outw(EEPROM_READ + index, ioaddr + 10); | 385 | outw(EEPROM_READ + index, ioaddr + 10); |
377 | /* Reading the eeprom takes 162 us */ | 386 | /* Reading the eeprom takes 162 us */ |
378 | for (i = 1620; i >= 0; i--) | 387 | for (i = 1620; i >= 0; i--) |
379 | if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0) | 388 | if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0) |
380 | break; | 389 | break; |
381 | return inw(ioaddr + 12); | 390 | return inw(ioaddr + 12); |
382 | } | 391 | } |
383 | 392 | ||
384 | /* | 393 | /* Set transceiver type, perhaps to something other than what the user |
385 | Set transceiver type, perhaps to something other than what the user | 394 | * specified in dev->if_port. |
386 | specified in dev->if_port. | 395 | */ |
387 | */ | 396 | |
388 | static void tc589_set_xcvr(struct net_device *dev, int if_port) | 397 | static void tc589_set_xcvr(struct net_device *dev, int if_port) |
389 | { | 398 | { |
390 | struct el3_private *lp = netdev_priv(dev); | 399 | struct el3_private *lp = netdev_priv(dev); |
391 | unsigned int ioaddr = dev->base_addr; | 400 | unsigned int ioaddr = dev->base_addr; |
392 | 401 | ||
393 | EL3WINDOW(0); | 402 | EL3WINDOW(0); |
394 | switch (if_port) { | 403 | switch (if_port) { |
395 | case 0: case 1: outw(0, ioaddr + 6); break; | 404 | case 0: |
396 | case 2: outw(3<<14, ioaddr + 6); break; | 405 | case 1: |
397 | case 3: outw(1<<14, ioaddr + 6); break; | 406 | outw(0, ioaddr + 6); |
398 | } | 407 | break; |
399 | /* On PCMCIA, this just turns on the LED */ | 408 | case 2: |
400 | outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); | 409 | outw(3<<14, ioaddr + 6); |
401 | /* 10baseT interface, enable link beat and jabber check. */ | 410 | break; |
402 | EL3WINDOW(4); | 411 | case 3: |
403 | outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA); | 412 | outw(1<<14, ioaddr + 6); |
404 | EL3WINDOW(1); | 413 | break; |
405 | if (if_port == 2) | 414 | } |
406 | lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000); | 415 | /* On PCMCIA, this just turns on the LED */ |
407 | else | 416 | outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); |
408 | lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800); | 417 | /* 10baseT interface, enable link beat and jabber check. */ |
418 | EL3WINDOW(4); | ||
419 | outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA); | ||
420 | EL3WINDOW(1); | ||
421 | if (if_port == 2) | ||
422 | lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000); | ||
423 | else | ||
424 | lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800); | ||
409 | } | 425 | } |
410 | 426 | ||
411 | static void dump_status(struct net_device *dev) | 427 | static void dump_status(struct net_device *dev) |
412 | { | 428 | { |
413 | unsigned int ioaddr = dev->base_addr; | 429 | unsigned int ioaddr = dev->base_addr; |
414 | EL3WINDOW(1); | 430 | EL3WINDOW(1); |
415 | netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n", | 431 | netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n", |
416 | inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS), | 432 | inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS), |
417 | inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE)); | 433 | inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE)); |
418 | EL3WINDOW(4); | 434 | EL3WINDOW(4); |
419 | netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n", | 435 | netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n", |
420 | inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08), | 436 | inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08), |
421 | inw(ioaddr+0x0a)); | 437 | inw(ioaddr+0x0a)); |
422 | EL3WINDOW(1); | 438 | EL3WINDOW(1); |
423 | } | 439 | } |
424 | 440 | ||
425 | /* Reset and restore all of the 3c589 registers. */ | 441 | /* Reset and restore all of the 3c589 registers. */ |
426 | static void tc589_reset(struct net_device *dev) | 442 | static void tc589_reset(struct net_device *dev) |
427 | { | 443 | { |
428 | unsigned int ioaddr = dev->base_addr; | 444 | unsigned int ioaddr = dev->base_addr; |
429 | int i; | 445 | int i; |
430 | 446 | ||
431 | EL3WINDOW(0); | 447 | EL3WINDOW(0); |
432 | outw(0x0001, ioaddr + 4); /* Activate board. */ | 448 | outw(0x0001, ioaddr + 4); /* Activate board. */ |
433 | outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ | 449 | outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ |
434 | 450 | ||
435 | /* Set the station address in window 2. */ | 451 | /* Set the station address in window 2. */ |
436 | EL3WINDOW(2); | 452 | EL3WINDOW(2); |
437 | for (i = 0; i < 6; i++) | 453 | for (i = 0; i < 6; i++) |
438 | outb(dev->dev_addr[i], ioaddr + i); | 454 | outb(dev->dev_addr[i], ioaddr + i); |
439 | 455 | ||
440 | tc589_set_xcvr(dev, dev->if_port); | 456 | tc589_set_xcvr(dev, dev->if_port); |
441 | 457 | ||
442 | /* Switch to the stats window, and clear all stats by reading. */ | 458 | /* Switch to the stats window, and clear all stats by reading. */ |
443 | outw(StatsDisable, ioaddr + EL3_CMD); | 459 | outw(StatsDisable, ioaddr + EL3_CMD); |
444 | EL3WINDOW(6); | 460 | EL3WINDOW(6); |
445 | for (i = 0; i < 9; i++) | 461 | for (i = 0; i < 9; i++) |
446 | inb(ioaddr+i); | 462 | inb(ioaddr+i); |
447 | inw(ioaddr + 10); | 463 | inw(ioaddr + 10); |
448 | inw(ioaddr + 12); | 464 | inw(ioaddr + 12); |
449 | 465 | ||
450 | /* Switch to register set 1 for normal use. */ | 466 | /* Switch to register set 1 for normal use. */ |
451 | EL3WINDOW(1); | 467 | EL3WINDOW(1); |
452 | 468 | ||
453 | set_rx_mode(dev); | 469 | set_rx_mode(dev); |
454 | outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ | 470 | outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ |
455 | outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ | 471 | outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ |
456 | outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ | 472 | outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ |
457 | /* Allow status bits to be seen. */ | 473 | /* Allow status bits to be seen. */ |
458 | outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); | 474 | outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); |
459 | /* Ack all pending events, and set active indicator mask. */ | 475 | /* Ack all pending events, and set active indicator mask. */ |
460 | outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, | 476 | outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, |
461 | ioaddr + EL3_CMD); | 477 | ioaddr + EL3_CMD); |
462 | outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull | 478 | outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull |
463 | | AdapterFailure, ioaddr + EL3_CMD); | 479 | | AdapterFailure, ioaddr + EL3_CMD); |
464 | } | 480 | } |
465 | 481 | ||
@@ -478,381 +494,406 @@ static const struct ethtool_ops netdev_ethtool_ops = { | |||
478 | 494 | ||
479 | static int el3_config(struct net_device *dev, struct ifmap *map) | 495 | static int el3_config(struct net_device *dev, struct ifmap *map) |
480 | { | 496 | { |
481 | if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { | 497 | if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { |
482 | if (map->port <= 3) { | 498 | if (map->port <= 3) { |
483 | dev->if_port = map->port; | 499 | dev->if_port = map->port; |
484 | netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); | 500 | netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); |
485 | tc589_set_xcvr(dev, dev->if_port); | 501 | tc589_set_xcvr(dev, dev->if_port); |
486 | } else | 502 | } else { |
487 | return -EINVAL; | 503 | return -EINVAL; |
488 | } | 504 | } |
489 | return 0; | 505 | } |
506 | return 0; | ||
490 | } | 507 | } |
491 | 508 | ||
492 | static int el3_open(struct net_device *dev) | 509 | static int el3_open(struct net_device *dev) |
493 | { | 510 | { |
494 | struct el3_private *lp = netdev_priv(dev); | 511 | struct el3_private *lp = netdev_priv(dev); |
495 | struct pcmcia_device *link = lp->p_dev; | 512 | struct pcmcia_device *link = lp->p_dev; |
496 | 513 | ||
497 | if (!pcmcia_dev_present(link)) | 514 | if (!pcmcia_dev_present(link)) |
498 | return -ENODEV; | 515 | return -ENODEV; |
499 | 516 | ||
500 | link->open++; | 517 | link->open++; |
501 | netif_start_queue(dev); | 518 | netif_start_queue(dev); |
502 | 519 | ||
503 | tc589_reset(dev); | 520 | tc589_reset(dev); |
504 | init_timer(&lp->media); | 521 | init_timer(&lp->media); |
505 | lp->media.function = media_check; | 522 | lp->media.function = media_check; |
506 | lp->media.data = (unsigned long) dev; | 523 | lp->media.data = (unsigned long) dev; |
507 | lp->media.expires = jiffies + HZ; | 524 | lp->media.expires = jiffies + HZ; |
508 | add_timer(&lp->media); | 525 | add_timer(&lp->media); |
509 | 526 | ||
510 | dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", | 527 | dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", |
511 | dev->name, inw(dev->base_addr + EL3_STATUS)); | 528 | dev->name, inw(dev->base_addr + EL3_STATUS)); |
512 | 529 | ||
513 | return 0; | 530 | return 0; |
514 | } | 531 | } |
515 | 532 | ||
516 | static void el3_tx_timeout(struct net_device *dev) | 533 | static void el3_tx_timeout(struct net_device *dev) |
517 | { | 534 | { |
518 | unsigned int ioaddr = dev->base_addr; | 535 | unsigned int ioaddr = dev->base_addr; |
519 | 536 | ||
520 | netdev_warn(dev, "Transmit timed out!\n"); | 537 | netdev_warn(dev, "Transmit timed out!\n"); |
521 | dump_status(dev); | 538 | dump_status(dev); |
522 | dev->stats.tx_errors++; | 539 | dev->stats.tx_errors++; |
523 | dev->trans_start = jiffies; /* prevent tx timeout */ | 540 | dev->trans_start = jiffies; /* prevent tx timeout */ |
524 | /* Issue TX_RESET and TX_START commands. */ | 541 | /* Issue TX_RESET and TX_START commands. */ |
525 | tc589_wait_for_completion(dev, TxReset); | 542 | tc589_wait_for_completion(dev, TxReset); |
526 | outw(TxEnable, ioaddr + EL3_CMD); | 543 | outw(TxEnable, ioaddr + EL3_CMD); |
527 | netif_wake_queue(dev); | 544 | netif_wake_queue(dev); |
528 | } | 545 | } |
529 | 546 | ||
530 | static void pop_tx_status(struct net_device *dev) | 547 | static void pop_tx_status(struct net_device *dev) |
531 | { | 548 | { |
532 | unsigned int ioaddr = dev->base_addr; | 549 | unsigned int ioaddr = dev->base_addr; |
533 | int i; | 550 | int i; |
534 | 551 | ||
535 | /* Clear the Tx status stack. */ | 552 | /* Clear the Tx status stack. */ |
536 | for (i = 32; i > 0; i--) { | 553 | for (i = 32; i > 0; i--) { |
537 | u_char tx_status = inb(ioaddr + TX_STATUS); | 554 | u_char tx_status = inb(ioaddr + TX_STATUS); |
538 | if (!(tx_status & 0x84)) break; | 555 | if (!(tx_status & 0x84)) |
539 | /* reset transmitter on jabber error or underrun */ | 556 | break; |
540 | if (tx_status & 0x30) | 557 | /* reset transmitter on jabber error or underrun */ |
541 | tc589_wait_for_completion(dev, TxReset); | 558 | if (tx_status & 0x30) |
542 | if (tx_status & 0x38) { | 559 | tc589_wait_for_completion(dev, TxReset); |
543 | netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status); | 560 | if (tx_status & 0x38) { |
544 | outw(TxEnable, ioaddr + EL3_CMD); | 561 | netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status); |
545 | dev->stats.tx_aborted_errors++; | 562 | outw(TxEnable, ioaddr + EL3_CMD); |
563 | dev->stats.tx_aborted_errors++; | ||
564 | } | ||
565 | outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ | ||
546 | } | 566 | } |
547 | outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ | ||
548 | } | ||
549 | } | 567 | } |
550 | 568 | ||
551 | static netdev_tx_t el3_start_xmit(struct sk_buff *skb, | 569 | static netdev_tx_t el3_start_xmit(struct sk_buff *skb, |
552 | struct net_device *dev) | 570 | struct net_device *dev) |
553 | { | 571 | { |
554 | unsigned int ioaddr = dev->base_addr; | 572 | unsigned int ioaddr = dev->base_addr; |
555 | struct el3_private *priv = netdev_priv(dev); | 573 | struct el3_private *priv = netdev_priv(dev); |
556 | unsigned long flags; | 574 | unsigned long flags; |
557 | 575 | ||
558 | netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n", | 576 | netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n", |
559 | (long)skb->len, inw(ioaddr + EL3_STATUS)); | 577 | (long)skb->len, inw(ioaddr + EL3_STATUS)); |
560 | 578 | ||
561 | spin_lock_irqsave(&priv->lock, flags); | 579 | spin_lock_irqsave(&priv->lock, flags); |
562 | 580 | ||
563 | dev->stats.tx_bytes += skb->len; | 581 | dev->stats.tx_bytes += skb->len; |
564 | 582 | ||
565 | /* Put out the doubleword header... */ | 583 | /* Put out the doubleword header... */ |
566 | outw(skb->len, ioaddr + TX_FIFO); | 584 | outw(skb->len, ioaddr + TX_FIFO); |
567 | outw(0x00, ioaddr + TX_FIFO); | 585 | outw(0x00, ioaddr + TX_FIFO); |
568 | /* ... and the packet rounded to a doubleword. */ | 586 | /* ... and the packet rounded to a doubleword. */ |
569 | outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); | 587 | outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); |
570 | 588 | ||
571 | if (inw(ioaddr + TX_FREE) <= 1536) { | 589 | if (inw(ioaddr + TX_FREE) <= 1536) { |
572 | netif_stop_queue(dev); | 590 | netif_stop_queue(dev); |
573 | /* Interrupt us when the FIFO has room for max-sized packet. */ | 591 | /* Interrupt us when the FIFO has room for max-sized packet. */ |
574 | outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); | 592 | outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); |
575 | } | 593 | } |
576 | 594 | ||
577 | pop_tx_status(dev); | 595 | pop_tx_status(dev); |
578 | spin_unlock_irqrestore(&priv->lock, flags); | 596 | spin_unlock_irqrestore(&priv->lock, flags); |
579 | dev_kfree_skb(skb); | 597 | dev_kfree_skb(skb); |
580 | 598 | ||
581 | return NETDEV_TX_OK; | 599 | return NETDEV_TX_OK; |
582 | } | 600 | } |
583 | 601 | ||
584 | /* The EL3 interrupt handler. */ | 602 | /* The EL3 interrupt handler. */ |
585 | static irqreturn_t el3_interrupt(int irq, void *dev_id) | 603 | static irqreturn_t el3_interrupt(int irq, void *dev_id) |
586 | { | 604 | { |
587 | struct net_device *dev = (struct net_device *) dev_id; | 605 | struct net_device *dev = (struct net_device *) dev_id; |
588 | struct el3_private *lp = netdev_priv(dev); | 606 | struct el3_private *lp = netdev_priv(dev); |
589 | unsigned int ioaddr; | 607 | unsigned int ioaddr; |
590 | __u16 status; | 608 | __u16 status; |
591 | int i = 0, handled = 1; | 609 | int i = 0, handled = 1; |
592 | 610 | ||
593 | if (!netif_device_present(dev)) | 611 | if (!netif_device_present(dev)) |
594 | return IRQ_NONE; | 612 | return IRQ_NONE; |
595 | 613 | ||
596 | ioaddr = dev->base_addr; | 614 | ioaddr = dev->base_addr; |
597 | 615 | ||
598 | netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); | 616 | netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); |
599 | 617 | ||
600 | spin_lock(&lp->lock); | 618 | spin_lock(&lp->lock); |
601 | while ((status = inw(ioaddr + EL3_STATUS)) & | 619 | while ((status = inw(ioaddr + EL3_STATUS)) & |
602 | (IntLatch | RxComplete | StatsFull)) { | 620 | (IntLatch | RxComplete | StatsFull)) { |
603 | if ((status & 0xe000) != 0x2000) { | 621 | if ((status & 0xe000) != 0x2000) { |
604 | netdev_dbg(dev, "interrupt from dead card\n"); | 622 | netdev_dbg(dev, "interrupt from dead card\n"); |
605 | handled = 0; | 623 | handled = 0; |
606 | break; | 624 | break; |
607 | } | 625 | } |
608 | if (status & RxComplete) | 626 | if (status & RxComplete) |
609 | el3_rx(dev); | 627 | el3_rx(dev); |
610 | if (status & TxAvailable) { | 628 | if (status & TxAvailable) { |
611 | netdev_dbg(dev, " TX room bit was handled.\n"); | 629 | netdev_dbg(dev, " TX room bit was handled.\n"); |
612 | /* There's room in the FIFO for a full-sized packet. */ | 630 | /* There's room in the FIFO for a full-sized packet. */ |
613 | outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); | 631 | outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); |
614 | netif_wake_queue(dev); | 632 | netif_wake_queue(dev); |
615 | } | 633 | } |
616 | if (status & TxComplete) | 634 | if (status & TxComplete) |
617 | pop_tx_status(dev); | 635 | pop_tx_status(dev); |
618 | if (status & (AdapterFailure | RxEarly | StatsFull)) { | 636 | if (status & (AdapterFailure | RxEarly | StatsFull)) { |
619 | /* Handle all uncommon interrupts. */ | 637 | /* Handle all uncommon interrupts. */ |
620 | if (status & StatsFull) /* Empty statistics. */ | 638 | if (status & StatsFull) /* Empty statistics. */ |
621 | update_stats(dev); | 639 | update_stats(dev); |
622 | if (status & RxEarly) { /* Rx early is unused. */ | 640 | if (status & RxEarly) { |
623 | el3_rx(dev); | 641 | /* Rx early is unused. */ |
624 | outw(AckIntr | RxEarly, ioaddr + EL3_CMD); | 642 | el3_rx(dev); |
625 | } | 643 | outw(AckIntr | RxEarly, ioaddr + EL3_CMD); |
626 | if (status & AdapterFailure) { | 644 | } |
627 | u16 fifo_diag; | 645 | if (status & AdapterFailure) { |
628 | EL3WINDOW(4); | 646 | u16 fifo_diag; |
629 | fifo_diag = inw(ioaddr + 4); | 647 | EL3WINDOW(4); |
630 | EL3WINDOW(1); | 648 | fifo_diag = inw(ioaddr + 4); |
631 | netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n", | 649 | EL3WINDOW(1); |
650 | netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n", | ||
632 | fifo_diag); | 651 | fifo_diag); |
633 | if (fifo_diag & 0x0400) { | 652 | if (fifo_diag & 0x0400) { |
634 | /* Tx overrun */ | 653 | /* Tx overrun */ |
635 | tc589_wait_for_completion(dev, TxReset); | 654 | tc589_wait_for_completion(dev, TxReset); |
636 | outw(TxEnable, ioaddr + EL3_CMD); | 655 | outw(TxEnable, ioaddr + EL3_CMD); |
656 | } | ||
657 | if (fifo_diag & 0x2000) { | ||
658 | /* Rx underrun */ | ||
659 | tc589_wait_for_completion(dev, RxReset); | ||
660 | set_rx_mode(dev); | ||
661 | outw(RxEnable, ioaddr + EL3_CMD); | ||
662 | } | ||
663 | outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); | ||
664 | } | ||
637 | } | 665 | } |
638 | if (fifo_diag & 0x2000) { | 666 | if (++i > 10) { |
639 | /* Rx underrun */ | 667 | netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n", |
640 | tc589_wait_for_completion(dev, RxReset); | 668 | status); |
641 | set_rx_mode(dev); | 669 | /* Clear all interrupts */ |
642 | outw(RxEnable, ioaddr + EL3_CMD); | 670 | outw(AckIntr | 0xFF, ioaddr + EL3_CMD); |
671 | break; | ||
643 | } | 672 | } |
644 | outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); | 673 | /* Acknowledge the IRQ. */ |
645 | } | 674 | outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); |
646 | } | 675 | } |
647 | if (++i > 10) { | 676 | lp->last_irq = jiffies; |
648 | netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n", | 677 | spin_unlock(&lp->lock); |
649 | status); | 678 | netdev_dbg(dev, "exiting interrupt, status %4.4x.\n", |
650 | /* Clear all interrupts */ | 679 | inw(ioaddr + EL3_STATUS)); |
651 | outw(AckIntr | 0xFF, ioaddr + EL3_CMD); | 680 | return IRQ_RETVAL(handled); |
652 | break; | ||
653 | } | ||
654 | /* Acknowledge the IRQ. */ | ||
655 | outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); | ||
656 | } | ||
657 | lp->last_irq = jiffies; | ||
658 | spin_unlock(&lp->lock); | ||
659 | netdev_dbg(dev, "exiting interrupt, status %4.4x.\n", | ||
660 | inw(ioaddr + EL3_STATUS)); | ||
661 | return IRQ_RETVAL(handled); | ||
662 | } | 681 | } |
663 | 682 | ||
664 | static void media_check(unsigned long arg) | 683 | static void media_check(unsigned long arg) |
665 | { | 684 | { |
666 | struct net_device *dev = (struct net_device *)(arg); | 685 | struct net_device *dev = (struct net_device *)(arg); |
667 | struct el3_private *lp = netdev_priv(dev); | 686 | struct el3_private *lp = netdev_priv(dev); |
668 | unsigned int ioaddr = dev->base_addr; | 687 | unsigned int ioaddr = dev->base_addr; |
669 | u16 media, errs; | 688 | u16 media, errs; |
670 | unsigned long flags; | 689 | unsigned long flags; |
671 | 690 | ||
672 | if (!netif_device_present(dev)) goto reschedule; | 691 | if (!netif_device_present(dev)) |
692 | goto reschedule; | ||
673 | 693 | ||
674 | /* Check for pending interrupt with expired latency timer: with | 694 | /* Check for pending interrupt with expired latency timer: with |
675 | this, we can limp along even if the interrupt is blocked */ | 695 | * this, we can limp along even if the interrupt is blocked |
676 | if ((inw(ioaddr + EL3_STATUS) & IntLatch) && | 696 | */ |
697 | if ((inw(ioaddr + EL3_STATUS) & IntLatch) && | ||
677 | (inb(ioaddr + EL3_TIMER) == 0xff)) { | 698 | (inb(ioaddr + EL3_TIMER) == 0xff)) { |
678 | if (!lp->fast_poll) | 699 | if (!lp->fast_poll) |
679 | netdev_warn(dev, "interrupt(s) dropped!\n"); | 700 | netdev_warn(dev, "interrupt(s) dropped!\n"); |
680 | 701 | ||
681 | local_irq_save(flags); | 702 | local_irq_save(flags); |
682 | el3_interrupt(dev->irq, dev); | 703 | el3_interrupt(dev->irq, dev); |
683 | local_irq_restore(flags); | 704 | local_irq_restore(flags); |
684 | 705 | ||
685 | lp->fast_poll = HZ; | 706 | lp->fast_poll = HZ; |
686 | } | 707 | } |
687 | if (lp->fast_poll) { | 708 | if (lp->fast_poll) { |
688 | lp->fast_poll--; | 709 | lp->fast_poll--; |
689 | lp->media.expires = jiffies + HZ/100; | 710 | lp->media.expires = jiffies + HZ/100; |
690 | add_timer(&lp->media); | 711 | add_timer(&lp->media); |
691 | return; | 712 | return; |
692 | } | 713 | } |
693 | 714 | ||
694 | /* lp->lock guards the EL3 window. Window should always be 1 except | 715 | /* lp->lock guards the EL3 window. Window should always be 1 except |
695 | when the lock is held */ | 716 | * when the lock is held |
696 | spin_lock_irqsave(&lp->lock, flags); | 717 | */ |
697 | EL3WINDOW(4); | 718 | |
698 | media = inw(ioaddr+WN4_MEDIA) & 0xc810; | 719 | spin_lock_irqsave(&lp->lock, flags); |
699 | 720 | EL3WINDOW(4); | |
700 | /* Ignore collisions unless we've had no irq's recently */ | 721 | media = inw(ioaddr+WN4_MEDIA) & 0xc810; |
701 | if (time_before(jiffies, lp->last_irq + HZ)) { | 722 | |
702 | media &= ~0x0010; | 723 | /* Ignore collisions unless we've had no irq's recently */ |
703 | } else { | 724 | if (time_before(jiffies, lp->last_irq + HZ)) { |
704 | /* Try harder to detect carrier errors */ | 725 | media &= ~0x0010; |
705 | EL3WINDOW(6); | 726 | } else { |
706 | outw(StatsDisable, ioaddr + EL3_CMD); | 727 | /* Try harder to detect carrier errors */ |
707 | errs = inb(ioaddr + 0); | 728 | EL3WINDOW(6); |
708 | outw(StatsEnable, ioaddr + EL3_CMD); | 729 | outw(StatsDisable, ioaddr + EL3_CMD); |
709 | dev->stats.tx_carrier_errors += errs; | 730 | errs = inb(ioaddr + 0); |
710 | if (errs || (lp->media_status & 0x0010)) media |= 0x0010; | 731 | outw(StatsEnable, ioaddr + EL3_CMD); |
711 | } | 732 | dev->stats.tx_carrier_errors += errs; |
733 | if (errs || (lp->media_status & 0x0010)) | ||
734 | media |= 0x0010; | ||
735 | } | ||
712 | 736 | ||
713 | if (media != lp->media_status) { | 737 | if (media != lp->media_status) { |
714 | if ((media & lp->media_status & 0x8000) && | 738 | if ((media & lp->media_status & 0x8000) && |
715 | ((lp->media_status ^ media) & 0x0800)) | 739 | ((lp->media_status ^ media) & 0x0800)) |
716 | netdev_info(dev, "%s link beat\n", | 740 | netdev_info(dev, "%s link beat\n", |
717 | (lp->media_status & 0x0800 ? "lost" : "found")); | 741 | (lp->media_status & 0x0800 ? "lost" : "found")); |
718 | else if ((media & lp->media_status & 0x4000) && | 742 | else if ((media & lp->media_status & 0x4000) && |
719 | ((lp->media_status ^ media) & 0x0010)) | 743 | ((lp->media_status ^ media) & 0x0010)) |
720 | netdev_info(dev, "coax cable %s\n", | 744 | netdev_info(dev, "coax cable %s\n", |
721 | (lp->media_status & 0x0010 ? "ok" : "problem")); | 745 | (lp->media_status & 0x0010 ? "ok" : "problem")); |
722 | if (dev->if_port == 0) { | 746 | if (dev->if_port == 0) { |
723 | if (media & 0x8000) { | 747 | if (media & 0x8000) { |
724 | if (media & 0x0800) | 748 | if (media & 0x0800) |
725 | netdev_info(dev, "flipped to 10baseT\n"); | 749 | netdev_info(dev, "flipped to 10baseT\n"); |
726 | else | 750 | else |
727 | tc589_set_xcvr(dev, 2); | 751 | tc589_set_xcvr(dev, 2); |
728 | } else if (media & 0x4000) { | 752 | } else if (media & 0x4000) { |
729 | if (media & 0x0010) | 753 | if (media & 0x0010) |
730 | tc589_set_xcvr(dev, 1); | 754 | tc589_set_xcvr(dev, 1); |
731 | else | 755 | else |
732 | netdev_info(dev, "flipped to 10base2\n"); | 756 | netdev_info(dev, "flipped to 10base2\n"); |
733 | } | 757 | } |
758 | } | ||
759 | lp->media_status = media; | ||
734 | } | 760 | } |
735 | lp->media_status = media; | ||
736 | } | ||
737 | 761 | ||
738 | EL3WINDOW(1); | 762 | EL3WINDOW(1); |
739 | spin_unlock_irqrestore(&lp->lock, flags); | 763 | spin_unlock_irqrestore(&lp->lock, flags); |
740 | 764 | ||
741 | reschedule: | 765 | reschedule: |
742 | lp->media.expires = jiffies + HZ; | 766 | lp->media.expires = jiffies + HZ; |
743 | add_timer(&lp->media); | 767 | add_timer(&lp->media); |
744 | } | 768 | } |
745 | 769 | ||
746 | static struct net_device_stats *el3_get_stats(struct net_device *dev) | 770 | static struct net_device_stats *el3_get_stats(struct net_device *dev) |
747 | { | 771 | { |
748 | struct el3_private *lp = netdev_priv(dev); | 772 | struct el3_private *lp = netdev_priv(dev); |
749 | unsigned long flags; | 773 | unsigned long flags; |
750 | struct pcmcia_device *link = lp->p_dev; | 774 | struct pcmcia_device *link = lp->p_dev; |
751 | 775 | ||
752 | if (pcmcia_dev_present(link)) { | 776 | if (pcmcia_dev_present(link)) { |
753 | spin_lock_irqsave(&lp->lock, flags); | 777 | spin_lock_irqsave(&lp->lock, flags); |
754 | update_stats(dev); | 778 | update_stats(dev); |
755 | spin_unlock_irqrestore(&lp->lock, flags); | 779 | spin_unlock_irqrestore(&lp->lock, flags); |
756 | } | 780 | } |
757 | return &dev->stats; | 781 | return &dev->stats; |
758 | } | 782 | } |
759 | 783 | ||
760 | /* | 784 | /* Update statistics. We change to register window 6, so this should be run |
761 | Update statistics. We change to register window 6, so this should be run | 785 | * single-threaded if the device is active. This is expected to be a rare |
762 | single-threaded if the device is active. This is expected to be a rare | 786 | * operation, and it's simpler for the rest of the driver to assume that |
763 | operation, and it's simpler for the rest of the driver to assume that | 787 | * window 1 is always valid rather than use a special window-state variable. |
764 | window 1 is always valid rather than use a special window-state variable. | 788 | * |
765 | 789 | * Caller must hold the lock for this | |
766 | Caller must hold the lock for this | ||
767 | */ | 790 | */ |
791 | |||
768 | static void update_stats(struct net_device *dev) | 792 | static void update_stats(struct net_device *dev) |
769 | { | 793 | { |
770 | unsigned int ioaddr = dev->base_addr; | 794 | unsigned int ioaddr = dev->base_addr; |
771 | 795 | ||
772 | netdev_dbg(dev, "updating the statistics.\n"); | 796 | netdev_dbg(dev, "updating the statistics.\n"); |
773 | /* Turn off statistics updates while reading. */ | 797 | /* Turn off statistics updates while reading. */ |
774 | outw(StatsDisable, ioaddr + EL3_CMD); | 798 | outw(StatsDisable, ioaddr + EL3_CMD); |
775 | /* Switch to the stats window, and read everything. */ | 799 | /* Switch to the stats window, and read everything. */ |
776 | EL3WINDOW(6); | 800 | EL3WINDOW(6); |
777 | dev->stats.tx_carrier_errors += inb(ioaddr + 0); | 801 | dev->stats.tx_carrier_errors += inb(ioaddr + 0); |
778 | dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); | 802 | dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); |
779 | /* Multiple collisions. */ inb(ioaddr + 2); | 803 | /* Multiple collisions. */ |
780 | dev->stats.collisions += inb(ioaddr + 3); | 804 | inb(ioaddr + 2); |
781 | dev->stats.tx_window_errors += inb(ioaddr + 4); | 805 | dev->stats.collisions += inb(ioaddr + 3); |
782 | dev->stats.rx_fifo_errors += inb(ioaddr + 5); | 806 | dev->stats.tx_window_errors += inb(ioaddr + 4); |
783 | dev->stats.tx_packets += inb(ioaddr + 6); | 807 | dev->stats.rx_fifo_errors += inb(ioaddr + 5); |
784 | /* Rx packets */ inb(ioaddr + 7); | 808 | dev->stats.tx_packets += inb(ioaddr + 6); |
785 | /* Tx deferrals */ inb(ioaddr + 8); | 809 | /* Rx packets */ |
786 | /* Rx octets */ inw(ioaddr + 10); | 810 | inb(ioaddr + 7); |
787 | /* Tx octets */ inw(ioaddr + 12); | 811 | /* Tx deferrals */ |
788 | 812 | inb(ioaddr + 8); | |
789 | /* Back to window 1, and turn statistics back on. */ | 813 | /* Rx octets */ |
790 | EL3WINDOW(1); | 814 | inw(ioaddr + 10); |
791 | outw(StatsEnable, ioaddr + EL3_CMD); | 815 | /* Tx octets */ |
816 | inw(ioaddr + 12); | ||
817 | |||
818 | /* Back to window 1, and turn statistics back on. */ | ||
819 | EL3WINDOW(1); | ||
820 | outw(StatsEnable, ioaddr + EL3_CMD); | ||
792 | } | 821 | } |
793 | 822 | ||
794 | static int el3_rx(struct net_device *dev) | 823 | static int el3_rx(struct net_device *dev) |
795 | { | 824 | { |
796 | unsigned int ioaddr = dev->base_addr; | 825 | unsigned int ioaddr = dev->base_addr; |
797 | int worklimit = 32; | 826 | int worklimit = 32; |
798 | short rx_status; | 827 | short rx_status; |
799 | 828 | ||
800 | netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n", | 829 | netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n", |
801 | inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); | 830 | inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); |
802 | while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) && | 831 | while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) && |
803 | worklimit > 0) { | 832 | worklimit > 0) { |
804 | worklimit--; | 833 | worklimit--; |
805 | if (rx_status & 0x4000) { /* Error, update stats. */ | 834 | if (rx_status & 0x4000) { /* Error, update stats. */ |
806 | short error = rx_status & 0x3800; | 835 | short error = rx_status & 0x3800; |
807 | dev->stats.rx_errors++; | 836 | dev->stats.rx_errors++; |
808 | switch (error) { | 837 | switch (error) { |
809 | case 0x0000: dev->stats.rx_over_errors++; break; | 838 | case 0x0000: |
810 | case 0x0800: dev->stats.rx_length_errors++; break; | 839 | dev->stats.rx_over_errors++; |
811 | case 0x1000: dev->stats.rx_frame_errors++; break; | 840 | break; |
812 | case 0x1800: dev->stats.rx_length_errors++; break; | 841 | case 0x0800: |
813 | case 0x2000: dev->stats.rx_frame_errors++; break; | 842 | dev->stats.rx_length_errors++; |
814 | case 0x2800: dev->stats.rx_crc_errors++; break; | 843 | break; |
815 | } | 844 | case 0x1000: |
816 | } else { | 845 | dev->stats.rx_frame_errors++; |
817 | short pkt_len = rx_status & 0x7ff; | 846 | break; |
818 | struct sk_buff *skb; | 847 | case 0x1800: |
819 | 848 | dev->stats.rx_length_errors++; | |
820 | skb = netdev_alloc_skb(dev, pkt_len + 5); | 849 | break; |
821 | 850 | case 0x2000: | |
822 | netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n", | 851 | dev->stats.rx_frame_errors++; |
852 | break; | ||
853 | case 0x2800: | ||
854 | dev->stats.rx_crc_errors++; | ||
855 | break; | ||
856 | } | ||
857 | } else { | ||
858 | short pkt_len = rx_status & 0x7ff; | ||
859 | struct sk_buff *skb; | ||
860 | |||
861 | skb = netdev_alloc_skb(dev, pkt_len + 5); | ||
862 | |||
863 | netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n", | ||
823 | pkt_len, rx_status); | 864 | pkt_len, rx_status); |
824 | if (skb != NULL) { | 865 | if (skb != NULL) { |
825 | skb_reserve(skb, 2); | 866 | skb_reserve(skb, 2); |
826 | insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), | 867 | insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), |
827 | (pkt_len+3)>>2); | 868 | (pkt_len+3)>>2); |
828 | skb->protocol = eth_type_trans(skb, dev); | 869 | skb->protocol = eth_type_trans(skb, dev); |
829 | netif_rx(skb); | 870 | netif_rx(skb); |
830 | dev->stats.rx_packets++; | 871 | dev->stats.rx_packets++; |
831 | dev->stats.rx_bytes += pkt_len; | 872 | dev->stats.rx_bytes += pkt_len; |
832 | } else { | 873 | } else { |
833 | netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n", | 874 | netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n", |
834 | pkt_len); | 875 | pkt_len); |
835 | dev->stats.rx_dropped++; | 876 | dev->stats.rx_dropped++; |
836 | } | 877 | } |
878 | } | ||
879 | /* Pop the top of the Rx FIFO */ | ||
880 | tc589_wait_for_completion(dev, RxDiscard); | ||
837 | } | 881 | } |
838 | /* Pop the top of the Rx FIFO */ | 882 | if (worklimit == 0) |
839 | tc589_wait_for_completion(dev, RxDiscard); | 883 | netdev_warn(dev, "too much work in el3_rx!\n"); |
840 | } | 884 | return 0; |
841 | if (worklimit == 0) | ||
842 | netdev_warn(dev, "too much work in el3_rx!\n"); | ||
843 | return 0; | ||
844 | } | 885 | } |
845 | 886 | ||
846 | static void set_rx_mode(struct net_device *dev) | 887 | static void set_rx_mode(struct net_device *dev) |
847 | { | 888 | { |
848 | unsigned int ioaddr = dev->base_addr; | 889 | unsigned int ioaddr = dev->base_addr; |
849 | u16 opts = SetRxFilter | RxStation | RxBroadcast; | 890 | u16 opts = SetRxFilter | RxStation | RxBroadcast; |
850 | 891 | ||
851 | if (dev->flags & IFF_PROMISC) | 892 | if (dev->flags & IFF_PROMISC) |
852 | opts |= RxMulticast | RxProm; | 893 | opts |= RxMulticast | RxProm; |
853 | else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) | 894 | else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) |
854 | opts |= RxMulticast; | 895 | opts |= RxMulticast; |
855 | outw(opts, ioaddr + EL3_CMD); | 896 | outw(opts, ioaddr + EL3_CMD); |
856 | } | 897 | } |
857 | 898 | ||
858 | static void set_multicast_list(struct net_device *dev) | 899 | static void set_multicast_list(struct net_device *dev) |
@@ -867,44 +908,44 @@ static void set_multicast_list(struct net_device *dev) | |||
867 | 908 | ||
868 | static int el3_close(struct net_device *dev) | 909 | static int el3_close(struct net_device *dev) |
869 | { | 910 | { |
870 | struct el3_private *lp = netdev_priv(dev); | 911 | struct el3_private *lp = netdev_priv(dev); |
871 | struct pcmcia_device *link = lp->p_dev; | 912 | struct pcmcia_device *link = lp->p_dev; |
872 | unsigned int ioaddr = dev->base_addr; | 913 | unsigned int ioaddr = dev->base_addr; |
873 | 914 | ||
874 | dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); | 915 | dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); |
916 | |||
917 | if (pcmcia_dev_present(link)) { | ||
918 | /* Turn off statistics ASAP. We update dev->stats below. */ | ||
919 | outw(StatsDisable, ioaddr + EL3_CMD); | ||
920 | |||
921 | /* Disable the receiver and transmitter. */ | ||
922 | outw(RxDisable, ioaddr + EL3_CMD); | ||
923 | outw(TxDisable, ioaddr + EL3_CMD); | ||
924 | |||
925 | if (dev->if_port == 2) | ||
926 | /* Turn off thinnet power. Green! */ | ||
927 | outw(StopCoax, ioaddr + EL3_CMD); | ||
928 | else if (dev->if_port == 1) { | ||
929 | /* Disable link beat and jabber */ | ||
930 | EL3WINDOW(4); | ||
931 | outw(0, ioaddr + WN4_MEDIA); | ||
932 | } | ||
875 | 933 | ||
876 | if (pcmcia_dev_present(link)) { | 934 | /* Switching back to window 0 disables the IRQ. */ |
877 | /* Turn off statistics ASAP. We update dev->stats below. */ | 935 | EL3WINDOW(0); |
878 | outw(StatsDisable, ioaddr + EL3_CMD); | 936 | /* But we explicitly zero the IRQ line select anyway. */ |
937 | outw(0x0f00, ioaddr + WN0_IRQ); | ||
879 | 938 | ||
880 | /* Disable the receiver and transmitter. */ | 939 | /* Check if the card still exists */ |
881 | outw(RxDisable, ioaddr + EL3_CMD); | 940 | if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000) |
882 | outw(TxDisable, ioaddr + EL3_CMD); | 941 | update_stats(dev); |
883 | |||
884 | if (dev->if_port == 2) | ||
885 | /* Turn off thinnet power. Green! */ | ||
886 | outw(StopCoax, ioaddr + EL3_CMD); | ||
887 | else if (dev->if_port == 1) { | ||
888 | /* Disable link beat and jabber */ | ||
889 | EL3WINDOW(4); | ||
890 | outw(0, ioaddr + WN4_MEDIA); | ||
891 | } | 942 | } |
892 | 943 | ||
893 | /* Switching back to window 0 disables the IRQ. */ | 944 | link->open--; |
894 | EL3WINDOW(0); | 945 | netif_stop_queue(dev); |
895 | /* But we explicitly zero the IRQ line select anyway. */ | 946 | del_timer_sync(&lp->media); |
896 | outw(0x0f00, ioaddr + WN0_IRQ); | ||
897 | |||
898 | /* Check if the card still exists */ | ||
899 | if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000) | ||
900 | update_stats(dev); | ||
901 | } | ||
902 | |||
903 | link->open--; | ||
904 | netif_stop_queue(dev); | ||
905 | del_timer_sync(&lp->media); | ||
906 | 947 | ||
907 | return 0; | 948 | return 0; |
908 | } | 949 | } |
909 | 950 | ||
910 | static const struct pcmcia_device_id tc589_ids[] = { | 951 | static const struct pcmcia_device_id tc589_ids[] = { |