1 /*
2 * linux/drivers/net/am79c961.c
3 *
4 * by Russell King <rmk@arm.linux.org.uk> 1995-2001.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Derived from various things including skeleton.c
11 *
12 * This is a special driver for the am79c961A Lance chip used in the
13 * Intel (formally Digital Equipment Corp) EBSA110 platform. Please
14 * note that this can not be built as a module (it doesn't make sense).
15 */
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/types.h>
19 #include <linux/fcntl.h>
20 #include <linux/interrupt.h>
21 #include <linux/ptrace.h>
22 #include <linux/ioport.h>
23 #include <linux/in.h>
24 #include <linux/slab.h>
25 #include <linux/string.h>
26 #include <linux/errno.h>
27 #include <linux/netdevice.h>
28 #include <linux/etherdevice.h>
29 #include <linux/skbuff.h>
30 #include <linux/delay.h>
31 #include <linux/init.h>
32 #include <linux/crc32.h>
33
34 #include <asm/system.h>
35 #include <asm/bitops.h>
36 #include <asm/irq.h>
37 #include <asm/io.h>
38 #include <asm/dma.h>
39
40 #define TX_BUFFERS 15
41 #define RX_BUFFERS 25
42
43 #include "am79c961a.h"
44
45 static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
46
47 static unsigned int net_debug = NET_DEBUG;
48
49 static const char version[] =
50 "am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n";
51
52 /* --------------------------------------------------------------------------- */
53
54 #ifdef __arm__
write_rreg(u_long base,u_int reg,u_int val)55 static void write_rreg(u_long base, u_int reg, u_int val)
56 {
57 __asm__("str%?h %1, [%2] @ NET_RAP
58 str%?h %0, [%2, #-4] @ NET_RDP
59 " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
60 }
61
read_rreg(u_long base_addr,u_int reg)62 static inline unsigned short read_rreg(u_long base_addr, u_int reg)
63 {
64 unsigned short v;
65 __asm__("str%?h %1, [%2] @ NET_RAP
66 ldr%?h %0, [%2, #-4] @ NET_RDP
67 " : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
68 return v;
69 }
70
write_ireg(u_long base,u_int reg,u_int val)71 static inline void write_ireg(u_long base, u_int reg, u_int val)
72 {
73 __asm__("str%?h %1, [%2] @ NET_RAP
74 str%?h %0, [%2, #8] @ NET_IDP
75 " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
76 }
77
78 #define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
79 #define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1))
80
81 static inline void
am_writebuffer(struct net_device * dev,u_int offset,unsigned char * buf,unsigned int length)82 am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
83 {
84 offset = ISAMEM_BASE + (offset << 1);
85 length = (length + 1) & ~1;
86 if ((int)buf & 2) {
87 __asm__ __volatile__("str%?h %2, [%0], #4"
88 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
89 buf += 2;
90 length -= 2;
91 }
92 while (length > 8) {
93 unsigned int tmp, tmp2;
94 __asm__ __volatile__("
95 ldm%?ia %1!, {%2, %3}
96 str%?h %2, [%0], #4
97 mov%? %2, %2, lsr #16
98 str%?h %2, [%0], #4
99 str%?h %3, [%0], #4
100 mov%? %3, %3, lsr #16
101 str%?h %3, [%0], #4
102 " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
103 : "0" (offset), "1" (buf));
104 length -= 8;
105 }
106 while (length > 0) {
107 __asm__ __volatile__("str%?h %2, [%0], #4"
108 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
109 buf += 2;
110 length -= 2;
111 }
112 }
113
114 static inline void
am_readbuffer(struct net_device * dev,u_int offset,unsigned char * buf,unsigned int length)115 am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
116 {
117 offset = ISAMEM_BASE + (offset << 1);
118 length = (length + 1) & ~1;
119 if ((int)buf & 2) {
120 unsigned int tmp;
121 __asm__ __volatile__("
122 ldr%?h %2, [%0], #4
123 str%?b %2, [%1], #1
124 mov%? %2, %2, lsr #8
125 str%?b %2, [%1], #1
126 " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
127 length -= 2;
128 }
129 while (length > 8) {
130 unsigned int tmp, tmp2, tmp3;
131 __asm__ __volatile__("
132 ldr%?h %2, [%0], #4
133 ldr%?h %3, [%0], #4
134 orr%? %2, %2, %3, lsl #16
135 ldr%?h %3, [%0], #4
136 ldr%?h %4, [%0], #4
137 orr%? %3, %3, %4, lsl #16
138 stm%?ia %1!, {%2, %3}
139 " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
140 : "0" (offset), "1" (buf));
141 length -= 8;
142 }
143 while (length > 0) {
144 unsigned int tmp;
145 __asm__ __volatile__("
146 ldr%?h %2, [%0], #4
147 str%?b %2, [%1], #1
148 mov%? %2, %2, lsr #8
149 str%?b %2, [%1], #1
150 " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
151 length -= 2;
152 }
153 }
154 #else
155 #error Not compatable
156 #endif
157
158 static int
am79c961_ramtest(struct net_device * dev,unsigned int val)159 am79c961_ramtest(struct net_device *dev, unsigned int val)
160 {
161 unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
162 int i, error = 0, errorcount = 0;
163
164 if (!buffer)
165 return 0;
166 memset (buffer, val, 65536);
167 am_writebuffer(dev, 0, buffer, 65536);
168 memset (buffer, val ^ 255, 65536);
169 am_readbuffer(dev, 0, buffer, 65536);
170 for (i = 0; i < 65536; i++) {
171 if (buffer[i] != val && !error) {
172 printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i);
173 error = 1;
174 errorcount ++;
175 } else if (error && buffer[i] == val) {
176 printk ("%05X\n", i);
177 error = 0;
178 }
179 }
180 if (error)
181 printk ("10000\n");
182 kfree (buffer);
183 return errorcount;
184 }
185
186 static void
am79c961_init_for_open(struct net_device * dev)187 am79c961_init_for_open(struct net_device *dev)
188 {
189 struct dev_priv *priv = (struct dev_priv *)dev->priv;
190 unsigned long flags;
191 unsigned char *p;
192 u_int hdr_addr, first_free_addr;
193 int i;
194
195 /*
196 * Stop the chip.
197 */
198 spin_lock_irqsave(priv->chip_lock, flags);
199 write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
200 spin_unlock_irqrestore(priv->chip_lock, flags);
201
202 write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */
203 write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */
204 write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */
205 write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */
206
207 for (i = LADRL; i <= LADRH; i++)
208 write_rreg (dev->base_addr, i, 0);
209
210 for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
211 write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
212
213 i = MODE_PORT_10BT;
214 if (dev->flags & IFF_PROMISC)
215 i |= MODE_PROMISC;
216
217 write_rreg (dev->base_addr, MODE, i);
218 write_rreg (dev->base_addr, POLLINT, 0);
219 write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
220 write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
221
222 first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
223 hdr_addr = 0;
224
225 priv->rxhead = 0;
226 priv->rxtail = 0;
227 priv->rxhdr = hdr_addr;
228
229 for (i = 0; i < RX_BUFFERS; i++) {
230 priv->rxbuffer[i] = first_free_addr;
231 am_writeword (dev, hdr_addr, first_free_addr);
232 am_writeword (dev, hdr_addr + 2, RMD_OWN);
233 am_writeword (dev, hdr_addr + 4, (-1600));
234 am_writeword (dev, hdr_addr + 6, 0);
235 first_free_addr += 1600;
236 hdr_addr += 8;
237 }
238 priv->txhead = 0;
239 priv->txtail = 0;
240 priv->txhdr = hdr_addr;
241 for (i = 0; i < TX_BUFFERS; i++) {
242 priv->txbuffer[i] = first_free_addr;
243 am_writeword (dev, hdr_addr, first_free_addr);
244 am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP);
245 am_writeword (dev, hdr_addr + 4, 0xf000);
246 am_writeword (dev, hdr_addr + 6, 0);
247 first_free_addr += 1600;
248 hdr_addr += 8;
249 }
250
251 write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
252 write_rreg (dev->base_addr, BASERXH, 0);
253 write_rreg (dev->base_addr, BASETXL, priv->txhdr);
254 write_rreg (dev->base_addr, BASERXH, 0);
255 write_rreg (dev->base_addr, CSR0, CSR0_STOP);
256 write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
257 write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
258 }
259
260 /*
261 * Open/initialize the board.
262 */
263 static int
am79c961_open(struct net_device * dev)264 am79c961_open(struct net_device *dev)
265 {
266 struct dev_priv *priv = (struct dev_priv *)dev->priv;
267 int ret;
268
269 memset (&priv->stats, 0, sizeof (priv->stats));
270
271 ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev);
272 if (ret)
273 return ret;
274
275 am79c961_init_for_open(dev);
276
277 netif_start_queue(dev);
278
279 return 0;
280 }
281
282 /*
283 * The inverse routine to am79c961_open().
284 */
285 static int
am79c961_close(struct net_device * dev)286 am79c961_close(struct net_device *dev)
287 {
288 struct dev_priv *priv = (struct dev_priv *)dev->priv;
289 unsigned long flags;
290
291 netif_stop_queue(dev);
292
293 spin_lock_irqsave(priv->chip_lock, flags);
294 write_rreg (dev->base_addr, CSR0, CSR0_STOP);
295 write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
296 spin_unlock_irqrestore(priv->chip_lock, flags);
297
298 free_irq (dev->irq, dev);
299
300 return 0;
301 }
302
303 /*
304 * Get the current statistics.
305 */
am79c961_getstats(struct net_device * dev)306 static struct net_device_stats *am79c961_getstats (struct net_device *dev)
307 {
308 struct dev_priv *priv = (struct dev_priv *)dev->priv;
309 return &priv->stats;
310 }
311
am79c961_mc_hash(struct dev_mc_list * dmi,unsigned short * hash)312 static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
313 {
314 if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
315 int idx, bit;
316 u32 crc;
317
318 crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
319
320 idx = crc >> 30;
321 bit = (crc >> 26) & 15;
322
323 hash[idx] |= 1 << bit;
324 }
325 }
326
327 /*
328 * Set or clear promiscuous/multicast mode filter for this adapter.
329 */
am79c961_setmulticastlist(struct net_device * dev)330 static void am79c961_setmulticastlist (struct net_device *dev)
331 {
332 struct dev_priv *priv = (struct dev_priv *)dev->priv;
333 unsigned long flags;
334 unsigned short multi_hash[4], mode;
335 int i, stopped;
336
337 mode = MODE_PORT_10BT;
338
339 if (dev->flags & IFF_PROMISC) {
340 mode |= MODE_PROMISC;
341 } else if (dev->flags & IFF_ALLMULTI) {
342 memset(multi_hash, 0xff, sizeof(multi_hash));
343 } else {
344 struct dev_mc_list *dmi;
345
346 memset(multi_hash, 0x00, sizeof(multi_hash));
347
348 for (dmi = dev->mc_list; dmi; dmi = dmi->next)
349 am79c961_mc_hash(dmi, multi_hash);
350 }
351
352 spin_lock_irqsave(priv->chip_lock, flags);
353
354 stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
355
356 if (!stopped) {
357 /*
358 * Put the chip into suspend mode
359 */
360 write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);
361
362 /*
363 * Spin waiting for chip to report suspend mode
364 */
365 while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {
366 spin_unlock_irqrestore(priv->chip_lock, flags);
367 nop();
368 spin_lock_irqsave(priv->chip_lock, flags);
369 }
370 }
371
372 /*
373 * Update the multicast hash table
374 */
375 for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
376 write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
377
378 /*
379 * Write the mode register
380 */
381 write_rreg(dev->base_addr, MODE, mode);
382
383 if (!stopped) {
384 /*
385 * Put the chip back into running mode
386 */
387 write_rreg(dev->base_addr, CTRL1, 0);
388 }
389
390 spin_unlock_irqrestore(priv->chip_lock, flags);
391 }
392
am79c961_timeout(struct net_device * dev)393 static void am79c961_timeout(struct net_device *dev)
394 {
395 printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",
396 dev->name);
397
398 /*
399 * ought to do some setup of the tx side here
400 */
401
402 netif_wake_queue(dev);
403 }
404
405 /*
406 * Transmit a packet
407 */
408 static int
am79c961_sendpacket(struct sk_buff * skb,struct net_device * dev)409 am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
410 {
411 struct dev_priv *priv = (struct dev_priv *)dev->priv;
412 unsigned int length = skb->len;
413 unsigned int hdraddr, bufaddr;
414 unsigned int head;
415 unsigned long flags;
416
417 /* FIXME: I thought the 79c961 could do padding - RMK ??? */
418 if(length < ETH_ZLEN)
419 {
420 skb = skb_padto(skb, ETH_ZLEN);
421 if(skb == NULL)
422 return 0;
423 length = ETH_ZLEN;
424 }
425
426 head = priv->txhead;
427 hdraddr = priv->txhdr + (head << 3);
428 bufaddr = priv->txbuffer[head];
429 head += 1;
430 if (head >= TX_BUFFERS)
431 head = 0;
432
433 am_writebuffer (dev, bufaddr, skb->data, length);
434 am_writeword (dev, hdraddr + 4, -length);
435 am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
436 priv->txhead = head;
437
438 spin_lock_irqsave(priv->chip_lock, flags);
439 write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
440 dev->trans_start = jiffies;
441 spin_unlock_irqrestore(priv->chip_lock, flags);
442
443 /*
444 * If the next packet is owned by the ethernet device,
445 * then the tx ring is full and we can't add another
446 * packet.
447 */
448 if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
449 netif_stop_queue(dev);
450
451 dev_kfree_skb(skb);
452
453 return 0;
454 }
455
456 /*
457 * If we have a good packet(s), get it/them out of the buffers.
458 */
459 static void
am79c961_rx(struct net_device * dev,struct dev_priv * priv)460 am79c961_rx(struct net_device *dev, struct dev_priv *priv)
461 {
462 do {
463 struct sk_buff *skb;
464 u_int hdraddr;
465 u_int pktaddr;
466 u_int status;
467 int len;
468
469 hdraddr = priv->rxhdr + (priv->rxtail << 3);
470 pktaddr = priv->rxbuffer[priv->rxtail];
471
472 status = am_readword (dev, hdraddr + 2);
473 if (status & RMD_OWN) /* do we own it? */
474 break;
475
476 priv->rxtail ++;
477 if (priv->rxtail >= RX_BUFFERS)
478 priv->rxtail = 0;
479
480 if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
481 am_writeword (dev, hdraddr + 2, RMD_OWN);
482 priv->stats.rx_errors ++;
483 if (status & RMD_ERR) {
484 if (status & RMD_FRAM)
485 priv->stats.rx_frame_errors ++;
486 if (status & RMD_CRC)
487 priv->stats.rx_crc_errors ++;
488 } else if (status & RMD_STP)
489 priv->stats.rx_length_errors ++;
490 continue;
491 }
492
493 len = am_readword(dev, hdraddr + 6);
494 skb = dev_alloc_skb(len + 2);
495
496 if (skb) {
497 skb->dev = dev;
498 skb_reserve(skb, 2);
499
500 am_readbuffer(dev, pktaddr, skb_put(skb, len), len);
501 am_writeword(dev, hdraddr + 2, RMD_OWN);
502 skb->protocol = eth_type_trans(skb, dev);
503 netif_rx(skb);
504 dev->last_rx = jiffies;
505 priv->stats.rx_bytes += len;
506 priv->stats.rx_packets ++;
507 } else {
508 am_writeword (dev, hdraddr + 2, RMD_OWN);
509 printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
510 priv->stats.rx_dropped ++;
511 break;
512 }
513 } while (1);
514 }
515
516 /*
517 * Update stats for the transmitted packet
518 */
519 static void
am79c961_tx(struct net_device * dev,struct dev_priv * priv)520 am79c961_tx(struct net_device *dev, struct dev_priv *priv)
521 {
522 do {
523 u_int hdraddr;
524 u_int status;
525
526 hdraddr = priv->txhdr + (priv->txtail << 3);
527 status = am_readword (dev, hdraddr + 2);
528 if (status & TMD_OWN)
529 break;
530
531 priv->txtail ++;
532 if (priv->txtail >= TX_BUFFERS)
533 priv->txtail = 0;
534
535 if (status & TMD_ERR) {
536 u_int status2;
537
538 priv->stats.tx_errors ++;
539
540 status2 = am_readword (dev, hdraddr + 6);
541
542 /*
543 * Clear the error byte
544 */
545 am_writeword (dev, hdraddr + 6, 0);
546
547 if (status2 & TST_RTRY)
548 priv->stats.collisions += 16;
549 if (status2 & TST_LCOL)
550 priv->stats.tx_window_errors ++;
551 if (status2 & TST_LCAR)
552 priv->stats.tx_carrier_errors ++;
553 if (status2 & TST_UFLO)
554 priv->stats.tx_fifo_errors ++;
555 continue;
556 }
557 priv->stats.tx_packets ++;
558 } while (priv->txtail != priv->txhead);
559
560 netif_wake_queue(dev);
561 }
562
563 static void
am79c961_interrupt(int irq,void * dev_id,struct pt_regs * regs)564 am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
565 {
566 struct net_device *dev = (struct net_device *)dev_id;
567 struct dev_priv *priv = (struct dev_priv *)dev->priv;
568 u_int status;
569
570 status = read_rreg(dev->base_addr, CSR0);
571 write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
572
573 if (status & CSR0_RINT)
574 am79c961_rx(dev, priv);
575 if (status & CSR0_TINT)
576 am79c961_tx(dev, priv);
577 if (status & CSR0_MISS)
578 priv->stats.rx_dropped ++;
579 }
580
581 /*
582 * Initialise the chip. Note that we always expect
583 * to be entered with interrupts enabled.
584 */
585 static int
am79c961_hw_init(struct net_device * dev)586 am79c961_hw_init(struct net_device *dev)
587 {
588 struct dev_priv *priv = (struct dev_priv *)dev->priv;
589
590 spin_lock_irq(priv->chip_lock);
591 write_rreg (dev->base_addr, CSR0, CSR0_STOP);
592 write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
593 spin_unlock_irq(priv->chip_lock);
594
595 am79c961_ramtest(dev, 0x66);
596 am79c961_ramtest(dev, 0x99);
597
598 return 0;
599 }
600
am79c961_banner(void)601 static void __init am79c961_banner(void)
602 {
603 static unsigned version_printed;
604
605 if (net_debug && version_printed++ == 0)
606 printk(KERN_INFO "%s", version);
607 }
608
am79c961_init(void)609 static int __init am79c961_init(void)
610 {
611 struct net_device *dev;
612 struct dev_priv *priv;
613 int i, ret;
614
615 dev = init_etherdev(NULL, sizeof(struct dev_priv));
616 ret = -ENOMEM;
617 if (!dev)
618 goto out;
619
620 priv = dev->priv;
621
622 /*
623 * Fixed address and IRQ lines here.
624 * The PNP initialisation should have been
625 * done by the ether bootp loader.
626 */
627 dev->base_addr = 0x220;
628 dev->irq = IRQ_EBSA110_ETHERNET;
629
630 /*
631 * Reset the device.
632 */
633 inb(dev->base_addr + NET_RESET);
634 udelay(5);
635
636 /*
637 * Check the manufacturer part of the
638 * ether address.
639 */
640 ret = -ENODEV;
641 if (inb(dev->base_addr) != 0x08 ||
642 inb(dev->base_addr + 2) != 0x00 ||
643 inb(dev->base_addr + 4) != 0x2b)
644 goto nodev;
645
646 if (!request_region(dev->base_addr, 0x18, dev->name))
647 goto nodev;
648
649 am79c961_banner();
650 printk(KERN_INFO "%s: ether address ", dev->name);
651
652 /* Retrive and print the ethernet address. */
653 for (i = 0; i < 6; i++) {
654 dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
655 printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
656 }
657
658 if (am79c961_hw_init(dev))
659 goto release;
660
661 dev->open = am79c961_open;
662 dev->stop = am79c961_close;
663 dev->hard_start_xmit = am79c961_sendpacket;
664 dev->get_stats = am79c961_getstats;
665 dev->set_multicast_list = am79c961_setmulticastlist;
666 dev->tx_timeout = am79c961_timeout;
667
668 return 0;
669
670 release:
671 release_region(dev->base_addr, 0x18);
672 nodev:
673 unregister_netdev(dev);
674 kfree(dev);
675 out:
676 return ret;
677 }
678
679 __initcall(am79c961_init);
680