blob: 94d9969ec0bbfa697c8d2e2487d58fcd032e51aa [file] [log] [blame]
Jeff Garzikd7fbeba2006-05-24 01:31:14 -04001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002net-3-driver for the IBM LAN Adapter/A
3
4This is an extension to the Linux operating system, and is covered by the
5same GNU General Public License that covers that work.
6
7Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
8 alfred.arnold@lancom.de)
9
10This driver is based both on the SK_MCA driver, which is itself based on the
11SK_G16 and 3C523 driver.
12
13paper sources:
Jeff Garzikd7fbeba2006-05-24 01:31:14 -040014 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 Hans-Peter Messmer for the basic Microchannel stuff
Jeff Garzikd7fbeba2006-05-24 01:31:14 -040016
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
18 for help on Ethernet driver programming
19
20 'DP83934CVUL-20/25 MHz SONIC-T Ethernet Controller Datasheet' by National
21 Semiconductor for info on the MAC chip
22
23 'LAN Technical Reference Ethernet Adapter Interface Version 1 Release 1.0
24 Document Number SC30-3661-00' by IBM for info on the adapter itself
25
Justin P. Mattock631dd1a2010-10-18 11:03:14 +020026 Also see http://www.national.com/analog
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28special acknowledgements to:
29 - Bob Eager for helping me out with documentation from IBM
Jeff Garzikd7fbeba2006-05-24 01:31:14 -040030 - Jim Shorney for his endless patience with me while I was using
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 him as a beta tester to trace down the address filter bug ;-)
32
33 Missing things:
34
35 -> set debug level via ioctl instead of compile-time switches
36 -> I didn't follow the development of the 2.1.x kernels, so my
Jeff Garzikd7fbeba2006-05-24 01:31:14 -040037 assumptions about which things changed with which kernel version
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 are probably nonsense
39
40History:
41 Nov 6th, 1999
42 startup from SK_MCA driver
43 Dec 6th, 1999
44 finally got docs about the card. A big thank you to Bob Eager!
45 Dec 12th, 1999
46 first packet received
47 Dec 13th, 1999
48 recv queue done, tcpdump works
49 Dec 15th, 1999
50 transmission part works
51 Dec 28th, 1999
52 added usage of the isa_functions for Linux 2.3 . Things should
53 still work with 2.0.x....
54 Jan 28th, 2000
55 in Linux 2.2.13, the version.h file mysteriously didn't get
56 included. Added a workaround for this. Futhermore, it now
57 not only compiles as a modules ;-)
58 Jan 30th, 2000
59 newer kernels automatically probe more than one board, so the
60 'startslot' as a variable is also needed here
61 Apr 12th, 2000
62 the interrupt mask register is not set 'hard' instead of individually
63 setting registers, since this seems to set bits that shouldn't be
64 set
65 May 21st, 2000
66 reset interrupt status immediately after CAM load
67 add a recovery delay after releasing the chip's reset line
68 May 24th, 2000
69 finally found the bug in the address filter setup - damned signed
70 chars!
71 June 1st, 2000
72 corrected version codes, added support for the latest 2.3 changes
73 Oct 28th, 2002
Alan Cox113aa832008-10-13 19:01:08 -070074 cleaned up for the 2.5 tree <alan@lxorguk.ukuu.org.uk>
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76 *************************************************************************/
77
78#include <linux/kernel.h>
79#include <linux/string.h>
80#include <linux/errno.h>
81#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070082#include <linux/interrupt.h>
83#include <linux/delay.h>
84#include <linux/time.h>
Jeff Garzik3df59202007-11-04 21:53:26 -050085#include <linux/mca.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#include <linux/module.h>
87#include <linux/netdevice.h>
88#include <linux/etherdevice.h>
Daniel Drake1f044932009-12-24 08:11:24 +000089#include <linux/if_ether.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#include <linux/skbuff.h>
91#include <linux/bitops.h>
92
93#include <asm/processor.h>
94#include <asm/io.h>
95
96#define _IBM_LANA_DRIVER_
97#include "ibmlana.h"
98
99#undef DEBUG
100
101#define DRV_NAME "ibmlana"
102
103/* ------------------------------------------------------------------------
104 * global static data - not more since we can handle multiple boards and
105 * have to pack all state info into the device struct!
106 * ------------------------------------------------------------------------ */
107
108static char *MediaNames[Media_Count] = {
109 "10BaseT", "10Base5", "Unknown", "10Base2"
110};
111
112/* ------------------------------------------------------------------------
113 * private subfunctions
114 * ------------------------------------------------------------------------ */
115
116#ifdef DEBUG
117 /* dump all registers */
118
119static void dumpregs(struct net_device *dev)
120{
121 int z;
122
123 for (z = 0; z < 160; z += 2) {
124 if (!(z & 15))
125 printk("REGS: %04x:", z);
126 printk(" %04x", inw(dev->base_addr + z));
127 if ((z & 15) == 14)
128 printk("\n");
129 }
130}
131
132/* dump parts of shared memory - only needed during debugging */
133
134static void dumpmem(struct net_device *dev, u32 start, u32 len)
135{
136 ibmlana_priv *priv = netdev_priv(dev);
137 int z;
138
139 printk("Address %04x:\n", start);
140 for (z = 0; z < len; z++) {
141 if ((z & 15) == 0)
142 printk("%04x:", z);
143 printk(" %02x", readb(priv->base + start + z));
144 if ((z & 15) == 15)
145 printk("\n");
146 }
147 if ((z & 15) != 0)
148 printk("\n");
149}
150
151/* print exact time - ditto */
152
153static void PrTime(void)
154{
155 struct timeval tv;
156
157 do_gettimeofday(&tv);
158 printk("%9d:%06d: ", (int) tv.tv_sec, (int) tv.tv_usec);
159}
160#endif /* DEBUG */
161
162/* deduce resources out of POS registers */
163
Jeff Garzik3df59202007-11-04 21:53:26 -0500164static void getaddrs(struct mca_device *mdev, int *base, int *memlen,
165 int *iobase, int *irq, ibmlana_medium *medium)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166{
167 u_char pos0, pos1;
168
Jeff Garzik3df59202007-11-04 21:53:26 -0500169 pos0 = mca_device_read_stored_pos(mdev, 2);
170 pos1 = mca_device_read_stored_pos(mdev, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172 *base = 0xc0000 + ((pos1 & 0xf0) << 9);
173 *memlen = (pos1 & 0x01) ? 0x8000 : 0x4000;
174 *iobase = (pos0 & 0xe0) << 7;
175 switch (pos0 & 0x06) {
176 case 0:
177 *irq = 5;
178 break;
179 case 2:
180 *irq = 15;
181 break;
182 case 4:
183 *irq = 10;
184 break;
185 case 6:
186 *irq = 11;
187 break;
188 }
189 *medium = (pos0 & 0x18) >> 3;
190}
191
192/* wait on register value with mask and timeout */
193
194static int wait_timeout(struct net_device *dev, int regoffs, u16 mask,
195 u16 value, int timeout)
196{
197 unsigned long fin = jiffies + timeout;
198
199 while (time_before(jiffies,fin))
200 if ((inw(dev->base_addr + regoffs) & mask) == value)
201 return 1;
202
203 return 0;
204}
205
206
207/* reset the whole board */
208
209static void ResetBoard(struct net_device *dev)
210{
211 unsigned char bcmval;
212
213 /* read original board control value */
214
215 bcmval = inb(dev->base_addr + BCMREG);
216
217 /* set reset bit for a while */
218
219 bcmval |= BCMREG_RESET;
220 outb(bcmval, dev->base_addr + BCMREG);
221 udelay(10);
222 bcmval &= ~BCMREG_RESET;
223 outb(bcmval, dev->base_addr + BCMREG);
224
225 /* switch over to RAM again */
226
227 bcmval |= BCMREG_RAMEN | BCMREG_RAMWIN;
228 outb(bcmval, dev->base_addr + BCMREG);
229}
230
231/* calculate RAM layout & set up descriptors in RAM */
232
233static void InitDscrs(struct net_device *dev)
234{
235 ibmlana_priv *priv = netdev_priv(dev);
236 u32 addr, baddr, raddr;
237 int z;
238 tda_t tda;
239 rda_t rda;
240 rra_t rra;
241
242 /* initialize RAM */
243
244 memset_io(priv->base, 0xaa,
245 dev->mem_start - dev->mem_start); /* XXX: typo? */
246
247 /* setup n TX descriptors - independent of RAM size */
248
249 priv->tdastart = addr = 0;
250 priv->txbufstart = baddr = sizeof(tda_t) * TXBUFCNT;
251 for (z = 0; z < TXBUFCNT; z++) {
252 tda.status = 0;
253 tda.config = 0;
254 tda.length = 0;
255 tda.fragcount = 1;
256 tda.startlo = baddr;
257 tda.starthi = 0;
258 tda.fraglength = 0;
259 if (z == TXBUFCNT - 1)
260 tda.link = priv->tdastart;
261 else
262 tda.link = addr + sizeof(tda_t);
263 tda.link |= 1;
264 memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
265 addr += sizeof(tda_t);
266 baddr += PKTSIZE;
267 }
268
269 /* calculate how many receive buffers fit into remaining memory */
270
271 priv->rxbufcnt = (dev->mem_end - dev->mem_start - baddr) / (sizeof(rra_t) + sizeof(rda_t) + PKTSIZE);
272
273 /* calculate receive addresses */
274
275 priv->rrastart = raddr = priv->txbufstart + (TXBUFCNT * PKTSIZE);
276 priv->rdastart = addr = priv->rrastart + (priv->rxbufcnt * sizeof(rra_t));
277 priv->rxbufstart = baddr = priv->rdastart + (priv->rxbufcnt * sizeof(rda_t));
Jeff Garzikd7fbeba2006-05-24 01:31:14 -0400278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 for (z = 0; z < priv->rxbufcnt; z++) {
280 rra.startlo = baddr;
281 rra.starthi = 0;
282 rra.cntlo = PKTSIZE >> 1;
283 rra.cnthi = 0;
284 memcpy_toio(priv->base + raddr, &rra, sizeof(rra_t));
285
286 rda.status = 0;
287 rda.length = 0;
288 rda.startlo = 0;
289 rda.starthi = 0;
290 rda.seqno = 0;
291 if (z < priv->rxbufcnt - 1)
292 rda.link = addr + sizeof(rda_t);
293 else
294 rda.link = 1;
295 rda.inuse = 1;
296 memcpy_toio(priv->base + addr, &rda, sizeof(rda_t));
297
298 baddr += PKTSIZE;
299 raddr += sizeof(rra_t);
300 addr += sizeof(rda_t);
301 }
302
303 /* initialize current pointers */
304
305 priv->nextrxdescr = 0;
306 priv->lastrxdescr = priv->rxbufcnt - 1;
307 priv->nexttxdescr = 0;
308 priv->currtxdescr = 0;
309 priv->txusedcnt = 0;
310 memset(priv->txused, 0, sizeof(priv->txused));
311}
312
313/* set up Rx + Tx descriptors in SONIC */
314
315static int InitSONIC(struct net_device *dev)
316{
317 ibmlana_priv *priv = netdev_priv(dev);
318
319 /* set up start & end of resource area */
320
321 outw(0, SONIC_URRA);
322 outw(priv->rrastart, dev->base_addr + SONIC_RSA);
323 outw(priv->rrastart + (priv->rxbufcnt * sizeof(rra_t)), dev->base_addr + SONIC_REA);
324 outw(priv->rrastart, dev->base_addr + SONIC_RRP);
325 outw(priv->rrastart, dev->base_addr + SONIC_RWP);
326
327 /* set EOBC so that only one packet goes into one buffer */
328
329 outw((PKTSIZE - 4) >> 1, dev->base_addr + SONIC_EOBC);
330
331 /* let SONIC read the first RRA descriptor */
332
333 outw(CMDREG_RRRA, dev->base_addr + SONIC_CMDREG);
334 if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_RRRA, 0, 2)) {
335 printk(KERN_ERR "%s: SONIC did not respond on RRRA command - giving up.", dev->name);
336 return 0;
337 }
338
339 /* point SONIC to the first RDA */
340
341 outw(0, dev->base_addr + SONIC_URDA);
342 outw(priv->rdastart, dev->base_addr + SONIC_CRDA);
343
344 /* set upper half of TDA address */
345
346 outw(0, dev->base_addr + SONIC_UTDA);
347
348 return 1;
349}
350
351/* stop SONIC so we can reinitialize it */
352
353static void StopSONIC(struct net_device *dev)
354{
355 /* disable interrupts */
356
357 outb(inb(dev->base_addr + BCMREG) & (~BCMREG_IEN), dev->base_addr + BCMREG);
358 outb(0, dev->base_addr + SONIC_IMREG);
359
360 /* reset the SONIC */
361
362 outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
363 udelay(10);
364 outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
365}
366
367/* initialize card and SONIC for proper operation */
368
369static void putcam(camentry_t * cams, int *camcnt, char *addr)
370{
371 camentry_t *pcam = cams + (*camcnt);
372 u8 *uaddr = (u8 *) addr;
373
374 pcam->index = *camcnt;
375 pcam->addr0 = (((u16) uaddr[1]) << 8) | uaddr[0];
376 pcam->addr1 = (((u16) uaddr[3]) << 8) | uaddr[2];
377 pcam->addr2 = (((u16) uaddr[5]) << 8) | uaddr[4];
378 (*camcnt)++;
379}
380
381static void InitBoard(struct net_device *dev)
382{
383 ibmlana_priv *priv = netdev_priv(dev);
384 int camcnt;
385 camentry_t cams[16];
386 u32 cammask;
Jiri Pirko22bedad32010-04-01 21:22:57 +0000387 struct netdev_hw_addr *ha;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 u16 rcrval;
389
390 /* reset the SONIC */
391
392 outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
393 udelay(10);
394
395 /* clear all spurious interrupts */
396
397 outw(inw(dev->base_addr + SONIC_ISREG), dev->base_addr + SONIC_ISREG);
398
399 /* set up the SONIC's bus interface - constant for this adapter -
400 must be done while the SONIC is in reset */
401
402 outw(DCREG_USR1 | DCREG_USR0 | DCREG_WC1 | DCREG_DW32, dev->base_addr + SONIC_DCREG);
403 outw(0, dev->base_addr + SONIC_DCREG2);
404
405 /* remove reset form the SONIC */
406
407 outw(0, dev->base_addr + SONIC_CMDREG);
408 udelay(10);
409
410 /* data sheet requires URRA to be programmed before setting up the CAM contents */
411
412 outw(0, dev->base_addr + SONIC_URRA);
413
414 /* program the CAM entry 0 to the device address */
415
416 camcnt = 0;
417 putcam(cams, &camcnt, dev->dev_addr);
418
419 /* start putting the multicast addresses into the CAM list. Stop if
420 it is full. */
421
Jiri Pirko22bedad32010-04-01 21:22:57 +0000422 netdev_for_each_mc_addr(ha, dev) {
423 putcam(cams, &camcnt, ha->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 if (camcnt == 16)
425 break;
426 }
427
428 /* calculate CAM mask */
429
430 cammask = (1 << camcnt) - 1;
431
432 /* feed CDA into SONIC, initialize RCR value (always get broadcasts) */
433
434 memcpy_toio(priv->base, cams, sizeof(camentry_t) * camcnt);
435 memcpy_toio(priv->base + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask));
436
437#ifdef DEBUG
438 printk("CAM setup:\n");
439 dumpmem(dev, 0, sizeof(camentry_t) * camcnt + sizeof(cammask));
440#endif
441
442 outw(0, dev->base_addr + SONIC_CAMPTR);
443 outw(camcnt, dev->base_addr + SONIC_CAMCNT);
444 outw(CMDREG_LCAM, dev->base_addr + SONIC_CMDREG);
445 if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_LCAM, 0, 2)) {
446 printk(KERN_ERR "%s:SONIC did not respond on LCAM command - giving up.", dev->name);
447 return;
448 } else {
449 /* clear interrupt condition */
450
451 outw(ISREG_LCD, dev->base_addr + SONIC_ISREG);
452
453#ifdef DEBUG
454 printk("Loading CAM done, address pointers %04x:%04x\n",
455 inw(dev->base_addr + SONIC_URRA),
456 inw(dev->base_addr + SONIC_CAMPTR));
457 {
458 int z;
459
460 printk("\n-->CAM: PTR %04x CNT %04x\n",
461 inw(dev->base_addr + SONIC_CAMPTR),
462 inw(dev->base_addr + SONIC_CAMCNT));
463 outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
464 for (z = 0; z < camcnt; z++) {
465 outw(z, dev->base_addr + SONIC_CAMEPTR);
466 printk("Entry %d: %04x %04x %04x\n", z,
467 inw(dev->base_addr + SONIC_CAMADDR0),
468 inw(dev->base_addr + SONIC_CAMADDR1),
469 inw(dev->base_addr + SONIC_CAMADDR2));
470 }
471 outw(0, dev->base_addr + SONIC_CMDREG);
472 }
473#endif
474 }
475
476 rcrval = RCREG_BRD | RCREG_LB_NONE;
477
478 /* if still multicast addresses left or ALLMULTI is set, set the multicast
479 enable bit */
480
Jiri Pirko22bedad32010-04-01 21:22:57 +0000481 if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > camcnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 rcrval |= RCREG_AMC;
483
484 /* promiscous mode ? */
485
486 if (dev->flags & IFF_PROMISC)
487 rcrval |= RCREG_PRO;
488
489 /* program receive mode */
490
491 outw(rcrval, dev->base_addr + SONIC_RCREG);
492#ifdef DEBUG
493 printk("\nRCRVAL: %04x\n", rcrval);
494#endif
495
496 /* set up descriptors in shared memory + feed them into SONIC registers */
497
498 InitDscrs(dev);
499 if (!InitSONIC(dev))
500 return;
501
502 /* reset all pending interrupts */
503
504 outw(0xffff, dev->base_addr + SONIC_ISREG);
505
506 /* enable transmitter + receiver interrupts */
507
508 outw(CMDREG_RXEN, dev->base_addr + SONIC_CMDREG);
509 outw(IMREG_PRXEN | IMREG_RBEEN | IMREG_PTXEN | IMREG_TXEREN, dev->base_addr + SONIC_IMREG);
510
511 /* turn on card interrupts */
512
513 outb(inb(dev->base_addr + BCMREG) | BCMREG_IEN, dev->base_addr + BCMREG);
514
515#ifdef DEBUG
516 printk("Register dump after initialization:\n");
517 dumpregs(dev);
518#endif
519}
520
521/* start transmission of a descriptor */
522
523static void StartTx(struct net_device *dev, int descr)
524{
525 ibmlana_priv *priv = netdev_priv(dev);
526 int addr;
527
528 addr = priv->tdastart + (descr * sizeof(tda_t));
529
530 /* put descriptor address into SONIC */
531
532 outw(addr, dev->base_addr + SONIC_CTDA);
533
534 /* trigger transmitter */
535
536 priv->currtxdescr = descr;
537 outw(CMDREG_TXP, dev->base_addr + SONIC_CMDREG);
538}
539
540/* ------------------------------------------------------------------------
541 * interrupt handler(s)
542 * ------------------------------------------------------------------------ */
543
544/* receive buffer area exhausted */
545
546static void irqrbe_handler(struct net_device *dev)
547{
548 ibmlana_priv *priv = netdev_priv(dev);
549
550 /* point the SONIC back to the RRA start */
551
552 outw(priv->rrastart, dev->base_addr + SONIC_RRP);
553 outw(priv->rrastart, dev->base_addr + SONIC_RWP);
554}
555
556/* receive interrupt */
557
558static void irqrx_handler(struct net_device *dev)
559{
560 ibmlana_priv *priv = netdev_priv(dev);
561 rda_t rda;
562 u32 rdaaddr, lrdaaddr;
563
564 /* loop until ... */
565
566 while (1) {
567 /* read descriptor that was next to be filled by SONIC */
568
569 rdaaddr = priv->rdastart + (priv->nextrxdescr * sizeof(rda_t));
570 lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t));
571 memcpy_fromio(&rda, priv->base + rdaaddr, sizeof(rda_t));
572
Jeff Garzikd7fbeba2006-05-24 01:31:14 -0400573 /* iron out upper word halves of fields we use - SONIC will duplicate
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 bits 0..15 to 16..31 */
575
576 rda.status &= 0xffff;
577 rda.length &= 0xffff;
578 rda.startlo &= 0xffff;
579
580 /* stop if the SONIC still owns it, i.e. there is no data for us */
581
582 if (rda.inuse)
583 break;
584
585 /* good packet? */
586
587 else if (rda.status & RCREG_PRX) {
588 struct sk_buff *skb;
589
590 /* fetch buffer */
591
592 skb = dev_alloc_skb(rda.length + 2);
593 if (skb == NULL)
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700594 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 else {
596 /* copy out data */
597
598 memcpy_fromio(skb_put(skb, rda.length),
599 priv->base +
600 rda.startlo, rda.length);
601
602 /* set up skb fields */
603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 skb->protocol = eth_type_trans(skb, dev);
Eric Dumazetbc8acf22010-09-02 13:07:41 -0700605 skb_checksum_none_assert(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 /* bookkeeping */
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700608 dev->stats.rx_packets++;
609 dev->stats.rx_bytes += rda.length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 /* pass to the upper layers */
612 netif_rx(skb);
613 }
614 }
615
616 /* otherwise check error status bits and increase statistics */
617
618 else {
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700619 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 if (rda.status & RCREG_FAER)
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700621 dev->stats.rx_frame_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 if (rda.status & RCREG_CRCR)
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700623 dev->stats.rx_crc_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 }
625
626 /* descriptor processed, will become new last descriptor in queue */
627
628 rda.link = 1;
629 rda.inuse = 1;
630 memcpy_toio(priv->base + rdaaddr, &rda,
631 sizeof(rda_t));
632
633 /* set up link and EOL = 0 in currently last descriptor. Only write
634 the link field since the SONIC may currently already access the
635 other fields. */
636
637 memcpy_toio(priv->base + lrdaaddr + 20, &rdaaddr, 4);
638
639 /* advance indices */
640
641 priv->lastrxdescr = priv->nextrxdescr;
642 if ((++priv->nextrxdescr) >= priv->rxbufcnt)
643 priv->nextrxdescr = 0;
644 }
645}
646
647/* transmit interrupt */
648
649static void irqtx_handler(struct net_device *dev)
650{
651 ibmlana_priv *priv = netdev_priv(dev);
652 tda_t tda;
653
654 /* fetch descriptor (we forgot the size ;-) */
655 memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
656
657 /* update statistics */
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700658 dev->stats.tx_packets++;
659 dev->stats.tx_bytes += tda.length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661 /* update our pointers */
662 priv->txused[priv->currtxdescr] = 0;
663 priv->txusedcnt--;
664
665 /* if there are more descriptors present in RAM, start them */
666 if (priv->txusedcnt > 0)
667 StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);
668
669 /* tell the upper layer we can go on transmitting */
670 netif_wake_queue(dev);
671}
672
673static void irqtxerr_handler(struct net_device *dev)
674{
675 ibmlana_priv *priv = netdev_priv(dev);
676 tda_t tda;
677
678 /* fetch descriptor to check status */
679 memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
680
681 /* update statistics */
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700682 dev->stats.tx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 if (tda.status & (TCREG_NCRS | TCREG_CRSL))
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700684 dev->stats.tx_carrier_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (tda.status & TCREG_EXC)
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700686 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (tda.status & TCREG_OWC)
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700688 dev->stats.tx_window_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (tda.status & TCREG_FU)
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700690 dev->stats.tx_fifo_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 /* update our pointers */
693 priv->txused[priv->currtxdescr] = 0;
694 priv->txusedcnt--;
695
696 /* if there are more descriptors present in RAM, start them */
697 if (priv->txusedcnt > 0)
698 StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);
699
700 /* tell the upper layer we can go on transmitting */
701 netif_wake_queue(dev);
702}
703
704/* general interrupt entry */
705
Jeff Garzik28fc1f52007-10-29 05:46:16 -0400706static irqreturn_t irq_handler(int dummy, void *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
Jeff Garzik28fc1f52007-10-29 05:46:16 -0400708 struct net_device *dev = device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 u16 ival;
710
711 /* in case we're not meant... */
712 if (!(inb(dev->base_addr + BCMREG) & BCMREG_IPEND))
713 return IRQ_NONE;
714
715 /* loop through the interrupt bits until everything is clear */
716 while (1) {
717 ival = inw(dev->base_addr + SONIC_ISREG);
718
719 if (ival & ISREG_RBE) {
720 irqrbe_handler(dev);
721 outw(ISREG_RBE, dev->base_addr + SONIC_ISREG);
722 }
723 if (ival & ISREG_PKTRX) {
724 irqrx_handler(dev);
725 outw(ISREG_PKTRX, dev->base_addr + SONIC_ISREG);
726 }
727 if (ival & ISREG_TXDN) {
728 irqtx_handler(dev);
729 outw(ISREG_TXDN, dev->base_addr + SONIC_ISREG);
730 }
731 if (ival & ISREG_TXER) {
732 irqtxerr_handler(dev);
733 outw(ISREG_TXER, dev->base_addr + SONIC_ISREG);
734 }
735 break;
736 }
737 return IRQ_HANDLED;
738}
739
740/* ------------------------------------------------------------------------
741 * driver methods
742 * ------------------------------------------------------------------------ */
743
744/* MCA info */
745
Jeff Garzik3df59202007-11-04 21:53:26 -0500746#if 0 /* info available elsewhere, but this is kept for reference */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747static int ibmlana_getinfo(char *buf, int slot, void *d)
748{
749 int len = 0, i;
750 struct net_device *dev = (struct net_device *) d;
751 ibmlana_priv *priv;
752
753 /* can't say anything about an uninitialized device... */
754
755 if (dev == NULL)
756 return len;
757 priv = netdev_priv(dev);
758
759 /* print info */
760
761 len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
762 len += sprintf(buf + len, "I/O: %#lx\n", dev->base_addr);
763 len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, dev->mem_end - 1);
764 len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]);
765 len += sprintf(buf + len, "Device: %s\n", dev->name);
766 len += sprintf(buf + len, "MAC address:");
767 for (i = 0; i < 6; i++)
768 len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
769 buf[len++] = '\n';
770 buf[len] = 0;
771
772 return len;
773}
Jeff Garzik3df59202007-11-04 21:53:26 -0500774#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776/* open driver. Means also initialization and start of LANCE */
777
778static int ibmlana_open(struct net_device *dev)
779{
780 int result;
781 ibmlana_priv *priv = netdev_priv(dev);
782
783 /* register resources - only necessary for IRQ */
784
Thomas Gleixner1fb9df52006-07-01 19:29:39 -0700785 result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (result != 0) {
787 printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq);
788 return result;
789 }
790 dev->irq = priv->realirq;
791
792 /* set up the card and SONIC */
793 InitBoard(dev);
794
795 /* initialize operational flags */
796 netif_start_queue(dev);
797 return 0;
798}
799
800/* close driver. Shut down board and free allocated resources */
801
802static int ibmlana_close(struct net_device *dev)
803{
804 /* turn off board */
805
806 /* release resources */
807 if (dev->irq != 0)
808 free_irq(dev->irq, dev);
809 dev->irq = 0;
810 return 0;
811}
812
813/* transmit a block. */
814
Stephen Hemminger613573252009-08-31 19:50:58 +0000815static netdev_tx_t ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816{
817 ibmlana_priv *priv = netdev_priv(dev);
Patrick McHardy3790c8c2009-06-12 03:00:35 +0000818 int tmplen, addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 unsigned long flags;
820 tda_t tda;
821 int baddr;
822
823 /* find out if there are free slots for a frame to transmit. If not,
824 the upper layer is in deep desperation and we simply ignore the frame. */
825
826 if (priv->txusedcnt >= TXBUFCNT) {
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700827 dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 goto tx_done;
829 }
830
831 /* copy the frame data into the next free transmit buffer - fillup missing */
832 tmplen = skb->len;
833 if (tmplen < 60)
834 tmplen = 60;
835 baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE);
836 memcpy_toio(priv->base + baddr, skb->data, skb->len);
837
Jeff Garzikd7fbeba2006-05-24 01:31:14 -0400838 /* copy filler into RAM - in case we're filling up...
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 we're filling a bit more than necessary, but that doesn't harm
Jeff Garzikd7fbeba2006-05-24 01:31:14 -0400840 since the buffer is far larger...
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 Sorry Linus for the filler string but I couldn't resist ;-) */
842
843 if (tmplen > skb->len) {
844 char *fill = "NetBSD is a nice OS too! ";
845 unsigned int destoffs = skb->len, l = strlen(fill);
846
847 while (destoffs < tmplen) {
848 memcpy_toio(priv->base + baddr + destoffs, fill, l);
849 destoffs += l;
850 }
851 }
852
853 /* set up the new frame descriptor */
854 addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t));
855 memcpy_fromio(&tda, priv->base + addr, sizeof(tda_t));
856 tda.length = tda.fraglength = tmplen;
857 memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
858
859 /* if there were no active descriptors, trigger the SONIC */
860 spin_lock_irqsave(&priv->lock, flags);
861
862 priv->txusedcnt++;
863 priv->txused[priv->nexttxdescr] = 1;
864
865 /* are all transmission slots used up ? */
866 if (priv->txusedcnt >= TXBUFCNT)
867 netif_stop_queue(dev);
868
869 if (priv->txusedcnt == 1)
870 StartTx(dev, priv->nexttxdescr);
871 priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT;
872
873 spin_unlock_irqrestore(&priv->lock, flags);
874tx_done:
875 dev_kfree_skb(skb);
Patrick McHardy3790c8c2009-06-12 03:00:35 +0000876 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877}
878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879/* switch receiver mode. */
880
881static void ibmlana_set_multicast_list(struct net_device *dev)
882{
883 /* first stop the SONIC... */
884 StopSONIC(dev);
885 /* ...then reinit it with the new flags */
886 InitBoard(dev);
887}
888
889/* ------------------------------------------------------------------------
890 * hardware check
891 * ------------------------------------------------------------------------ */
892
Jeff Garzikfbe02d62007-11-04 21:52:49 -0500893static int ibmlana_irq;
894static int ibmlana_io;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895static int startslot; /* counts through slots when probing multiple devices */
896
Jeff Garzik3df59202007-11-04 21:53:26 -0500897static short ibmlana_adapter_ids[] __initdata = {
898 IBM_LANA_ID,
899 0x0000
900};
901
Adrian Bunk976006f2008-01-30 22:02:10 +0200902static char *ibmlana_adapter_names[] __devinitdata = {
Jeff Garzik3df59202007-11-04 21:53:26 -0500903 "IBM LAN Adapter/A",
904 NULL
905};
906
Stephen Hemmingerd9c6d502009-03-26 15:11:33 +0000907
908static const struct net_device_ops ibmlana_netdev_ops = {
909 .ndo_open = ibmlana_open,
910 .ndo_stop = ibmlana_close,
911 .ndo_start_xmit = ibmlana_tx,
912 .ndo_set_multicast_list = ibmlana_set_multicast_list,
913 .ndo_change_mtu = eth_change_mtu,
914 .ndo_set_mac_address = eth_mac_addr,
915 .ndo_validate_addr = eth_validate_addr,
916};
917
Adrian Bunkb54e4f82008-01-30 22:02:08 +0200918static int __devinit ibmlana_init_one(struct device *kdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
Jeff Garzik3df59202007-11-04 21:53:26 -0500920 struct mca_device *mdev = to_mca_device(kdev);
Jeff Garzikfbe02d62007-11-04 21:52:49 -0500921 struct net_device *dev;
Jeff Garzik3df59202007-11-04 21:53:26 -0500922 int slot = mdev->slot, z, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 int base = 0, irq = 0, iobase = 0, memlen = 0;
924 ibmlana_priv *priv;
925 ibmlana_medium medium;
926
Jeff Garzikfbe02d62007-11-04 21:52:49 -0500927 dev = alloc_etherdev(sizeof(ibmlana_priv));
928 if (!dev)
929 return -ENOMEM;
930
931 dev->irq = ibmlana_irq;
932 dev->base_addr = ibmlana_io;
933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 base = dev->mem_start;
935 irq = dev->irq;
936
Jeff Garzik3df59202007-11-04 21:53:26 -0500937 /* deduce card addresses */
938 getaddrs(mdev, &base, &memlen, &iobase, &irq, &medium);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Jeff Garzik3df59202007-11-04 21:53:26 -0500940 /* were we looking for something different ? */
941 if (dev->irq && dev->irq != irq) {
942 rc = -ENODEV;
943 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 }
Jeff Garzik3df59202007-11-04 21:53:26 -0500945 if (dev->mem_start && dev->mem_start != base) {
946 rc = -ENODEV;
Jeff Garzikfbe02d62007-11-04 21:52:49 -0500947 goto err_out;
948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 /* announce success */
951 printk(KERN_INFO "%s: IBM LAN Adapter/A found in slot %d\n", dev->name, slot + 1);
952
953 /* try to obtain I/O range */
954 if (!request_region(iobase, IBM_LANA_IORANGE, DRV_NAME)) {
955 printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", DRV_NAME, iobase);
956 startslot = slot + 1;
Jeff Garzikfbe02d62007-11-04 21:52:49 -0500957 rc = -EBUSY;
958 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 }
960
961 priv = netdev_priv(dev);
962 priv->slot = slot;
Jeff Garzik3df59202007-11-04 21:53:26 -0500963 priv->realirq = mca_device_transform_irq(mdev, irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 priv->medium = medium;
965 spin_lock_init(&priv->lock);
Jeff Garzikd7fbeba2006-05-24 01:31:14 -0400966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 /* set base + irq for this device (irq not allocated so far) */
968
969 dev->irq = 0;
970 dev->mem_start = base;
971 dev->mem_end = base + memlen;
972 dev->base_addr = iobase;
973
974 priv->base = ioremap(base, memlen);
975 if (!priv->base) {
976 printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME);
977 startslot = slot + 1;
Jeff Garzikfbe02d62007-11-04 21:52:49 -0500978 rc = -EBUSY;
979 goto err_out_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 }
981
Jeff Garzik3df59202007-11-04 21:53:26 -0500982 mca_device_set_name(mdev, ibmlana_adapter_names[mdev->index]);
983 mca_device_set_claim(mdev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 /* set methods */
Stephen Hemmingerd9c6d502009-03-26 15:11:33 +0000986 dev->netdev_ops = &ibmlana_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 dev->flags |= IFF_MULTICAST;
988
989 /* copy out MAC address */
990
Daniel Drake1f044932009-12-24 08:11:24 +0000991 for (z = 0; z < ETH_ALEN; z++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 dev->dev_addr[z] = inb(dev->base_addr + MACADDRPROM + z);
993
994 /* print config */
995
996 printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "
Johannes Berge1749612008-10-27 15:59:26 -0700997 "MAC address %pM.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 dev->name, priv->realirq, dev->base_addr,
999 dev->mem_start, dev->mem_end - 1,
Johannes Berge1749612008-10-27 15:59:26 -07001000 dev->dev_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]);
1002
1003 /* reset board */
1004
1005 ResetBoard(dev);
1006
1007 /* next probe will start at next slot */
1008
1009 startslot = slot + 1;
1010
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001011 rc = register_netdev(dev);
1012 if (rc)
1013 goto err_out_claimed;
1014
Jeff Garzik3df59202007-11-04 21:53:26 -05001015 dev_set_drvdata(kdev, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 return 0;
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001017
1018err_out_claimed:
Jeff Garzik3df59202007-11-04 21:53:26 -05001019 mca_device_set_claim(mdev, 0);
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001020 iounmap(priv->base);
1021err_out_reg:
1022 release_region(iobase, IBM_LANA_IORANGE);
1023err_out:
1024 free_netdev(dev);
1025 return rc;
1026}
1027
Jeff Garzik3df59202007-11-04 21:53:26 -05001028static int ibmlana_remove_one(struct device *kdev)
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001029{
Jeff Garzik3df59202007-11-04 21:53:26 -05001030 struct mca_device *mdev = to_mca_device(kdev);
1031 struct net_device *dev = dev_get_drvdata(kdev);
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001032 ibmlana_priv *priv = netdev_priv(dev);
1033
1034 unregister_netdev(dev);
1035 /*DeinitBoard(dev); */
1036 release_region(dev->base_addr, IBM_LANA_IORANGE);
Jeff Garzik3df59202007-11-04 21:53:26 -05001037 mca_device_set_claim(mdev, 0);
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001038 iounmap(priv->base);
1039 free_netdev(dev);
Jeff Garzik3df59202007-11-04 21:53:26 -05001040 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041}
1042
1043/* ------------------------------------------------------------------------
1044 * modularization support
1045 * ------------------------------------------------------------------------ */
1046
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001047module_param_named(irq, ibmlana_irq, int, 0);
1048module_param_named(io, ibmlana_io, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");
1050MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");
1051MODULE_LICENSE("GPL");
1052
Jeff Garzik3df59202007-11-04 21:53:26 -05001053static struct mca_driver ibmlana_driver = {
1054 .id_table = ibmlana_adapter_ids,
1055 .driver = {
1056 .name = "ibmlana",
1057 .bus = &mca_bus_type,
1058 .probe = ibmlana_init_one,
1059 .remove = ibmlana_remove_one,
1060 },
1061};
1062
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001063static int __init ibmlana_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
Jeff Garzik3df59202007-11-04 21:53:26 -05001065 return mca_register_driver(&ibmlana_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066}
1067
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001068static void __exit ibmlana_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
Jeff Garzik3df59202007-11-04 21:53:26 -05001070 mca_unregister_driver(&ibmlana_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071}
Jeff Garzikfbe02d62007-11-04 21:52:49 -05001072
1073module_init(ibmlana_init_module);
1074module_exit(ibmlana_cleanup_module);