* better
[mascara-docs.git] / i386 / linux-2.3.21 / drivers / net / am79c961a.c
blobcfb48ca0303eb238c0eeec5eabc8b492423582f5
1 /*
2 * linux/drivers/net/am79c961.c
4 * Derived from various things including skeleton.c
6 * R.M.King 1995.
7 */
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/types.h>
12 #include <linux/fcntl.h>
13 #include <linux/interrupt.h>
14 #include <linux/ptrace.h>
15 #include <linux/ioport.h>
16 #include <linux/in.h>
17 #include <linux/malloc.h>
18 #include <linux/string.h>
19 #include <linux/errno.h>
20 #include <linux/netdevice.h>
21 #include <linux/etherdevice.h>
22 #include <linux/skbuff.h>
24 #include <asm/system.h>
25 #include <asm/bitops.h>
26 #include <asm/io.h>
27 #include <asm/dma.h>
28 #include <asm/ecard.h>
29 #include <asm/delay.h>
31 #define TX_BUFFERS 15
32 #define RX_BUFFERS 25
34 #include "am79c961a.h"
36 static unsigned int net_debug = NET_DEBUG;
38 static void
39 am79c961_setmulticastlist (struct net_device *dev);
41 static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n";
43 #define FUNC_PROLOGUE \
44 struct dev_priv *priv = (struct dev_priv *)dev->priv
46 /* --------------------------------------------------------------------------- */
48 static void
49 write_rreg (unsigned long base, unsigned int reg, unsigned short val)
51 __asm__("
52 strh %1, [%2] @ NET_RAP
53 strh %0, [%2, #-4] @ NET_RDP
54 " : : "r" (val), "r" (reg), "r" (0xf0000464));
57 static inline void
58 write_ireg (unsigned long base, unsigned int reg, unsigned short val)
60 __asm__("
61 strh %1, [%2] @ NET_RAP
62 strh %0, [%2, #8] @ NET_RDP
63 " : : "r" (val), "r" (reg), "r" (0xf0000464));
66 #define am_writeword(dev,off,val)\
67 __asm__("\
68 strh %0, [%1]\
69 " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
71 static inline void
72 am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
74 offset = 0xe0000000 + (offset << 1);
75 length = (length + 1) & ~1;
76 if ((int)buf & 2) {
77 __asm__ __volatile__("
78 strh %2, [%0], #4
79 " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
80 buf += 2;
81 length -= 2;
83 while (length > 8) {
84 unsigned int tmp, tmp2;
85 __asm__ __volatile__("
86 ldmia %1!, {%2, %3}
87 strh %2, [%0], #4
88 mov %2, %2, lsr #16
89 strh %2, [%0], #4
90 strh %3, [%0], #4
91 mov %3, %3, lsr #16
92 strh %3, [%0], #4
93 " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
94 : "0" (offset), "1" (buf));
95 length -= 8;
97 while (length > 0) {
98 __asm__ __volatile__("
99 strh %2, [%0], #4
100 " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
101 buf += 2;
102 length -= 2;
106 static inline unsigned short
107 read_rreg (unsigned int base_addr, unsigned int reg)
109 unsigned short v;
110 __asm__("
111 strh %1, [%2] @ NET_RAP
112 ldrh %0, [%2, #-4] @ NET_IDP
113 " : "=r" (v): "r" (reg), "r" (0xf0000464));
114 return v;
117 static inline unsigned short
118 am_readword (struct net_device *dev, unsigned long off)
120 unsigned long address = 0xe0000000 + (off << 1);
121 unsigned short val;
123 __asm__("
124 ldrh %0, [%1]
125 " : "=r" (val): "r" (address));
126 return val;
129 static inline void
130 am_readbuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
132 offset = 0xe0000000 + (offset << 1);
133 length = (length + 1) & ~1;
134 if ((int)buf & 2) {
135 unsigned int tmp;
136 __asm__ __volatile__("
137 ldrh %2, [%0], #4
138 strb %2, [%1], #1
139 mov %2, %2, lsr #8
140 strb %2, [%1], #1
141 " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
142 length -= 2;
144 while (length > 8) {
145 unsigned int tmp, tmp2, tmp3;
146 __asm__ __volatile__("
147 ldrh %2, [%0], #4
148 ldrh %3, [%0], #4
149 orr %2, %2, %3, lsl #16
150 ldrh %3, [%0], #4
151 ldrh %4, [%0], #4
152 orr %3, %3, %4, lsl #16
153 stmia %1!, {%2, %3}
154 " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
155 : "0" (offset), "1" (buf));
156 length -= 8;
158 while (length > 0) {
159 unsigned int tmp;
160 __asm__ __volatile__("
161 ldrh %2, [%0], #4
162 strb %2, [%1], #1
163 mov %2, %2, lsr #8
164 strb %2, [%1], #1
165 " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
166 length -= 2;
170 static int
171 am79c961_ramtest(struct net_device *dev, unsigned int val)
173 unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
174 int i, error = 0, errorcount = 0;
176 if (!buffer)
177 return 0;
178 memset (buffer, val, 65536);
179 am_writebuffer(dev, 0, buffer, 65536);
180 memset (buffer, val ^ 255, 65536);
181 am_readbuffer(dev, 0, buffer, 65536);
182 for (i = 0; i < 65536; i++) {
183 if (buffer[i] != val && !error) {
184 printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i);
185 error = 1;
186 errorcount ++;
187 } else if (error && buffer[i] == val) {
188 printk ("%05X\n", i);
189 error = 0;
192 if (error)
193 printk ("10000\n");
194 kfree (buffer);
195 return errorcount;
198 static void
199 am79c961_init_for_open(struct net_device *dev)
201 struct dev_priv *priv = (struct dev_priv *)dev->priv;
202 unsigned long hdr_addr, first_free_addr;
203 unsigned long flags;
204 unsigned char *p;
205 int i;
207 save_flags_cli (flags);
209 write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
210 write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
212 restore_flags (flags);
214 first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
215 hdr_addr = 0;
217 priv->rxhead = 0;
218 priv->rxtail = 0;
219 priv->rxhdr = hdr_addr;
221 for (i = 0; i < RX_BUFFERS; i++) {
222 priv->rxbuffer[i] = first_free_addr;
223 am_writeword (dev, hdr_addr, first_free_addr);
224 am_writeword (dev, hdr_addr + 2, RMD_OWN);
225 am_writeword (dev, hdr_addr + 4, (-1600));
226 am_writeword (dev, hdr_addr + 6, 0);
227 first_free_addr += 1600;
228 hdr_addr += 8;
230 priv->txhead = 0;
231 priv->txtail = 0;
232 priv->txhdr = hdr_addr;
233 for (i = 0; i < TX_BUFFERS; i++) {
234 priv->txbuffer[i] = first_free_addr;
235 am_writeword (dev, hdr_addr, first_free_addr);
236 am_writeword (dev, hdr_addr + 2, 0);
237 am_writeword (dev, hdr_addr + 4, 0);
238 am_writeword (dev, hdr_addr + 6, 0);
239 first_free_addr += 1600;
240 hdr_addr += 8;
243 for (i = LADRL; i <= LADRH; i++)
244 write_rreg (dev->base_addr, i, 0);
246 for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
247 write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
249 i = MODE_PORT0;
250 if (dev->flags & IFF_PROMISC)
251 i |= MODE_PROMISC;
253 write_rreg (dev->base_addr, MODE, i);
254 write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
255 write_rreg (dev->base_addr, BASERXH, 0);
256 write_rreg (dev->base_addr, BASETXL, priv->txhdr);
257 write_rreg (dev->base_addr, BASERXH, 0);
258 write_rreg (dev->base_addr, POLLINT, 0);
259 write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
260 write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
261 write_rreg (dev->base_addr, CSR0, CSR0_STOP);
262 write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM);
263 write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
266 static int
267 am79c961_init(struct net_device *dev)
269 unsigned long flags;
271 am79c961_ramtest(dev, 0x66);
272 am79c961_ramtest(dev, 0x99);
274 save_flags_cli (flags);
276 write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
277 write_rreg (dev->base_addr, CSR0, CSR0_STOP);
278 write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
280 restore_flags (flags);
282 return 0;
286 * This is the real probe routine.
288 static int
289 am79c961_probe1(struct net_device *dev)
291 static unsigned version_printed = 0;
292 struct dev_priv *priv;
293 int i;
295 if (!dev->priv) {
296 dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL);
297 if (!dev->priv)
298 return -ENOMEM;
301 priv = (struct dev_priv *) dev->priv;
302 memset (priv, 0, sizeof(struct dev_priv));
305 * The PNP initialisation should have been done by the ether bootp loader.
307 inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */
309 udelay (5);
311 if (inb (dev->base_addr >> 1) != 0x08 ||
312 inb ((dev->base_addr >> 1) + 1) != 00 ||
313 inb ((dev->base_addr >> 1) + 2) != 0x2b) {
314 kfree (dev->priv);
315 dev->priv = NULL;
316 return -ENODEV;
320 * Ok, we've found a valid hw ID
323 if (net_debug && version_printed++ == 0)
324 printk (KERN_INFO "%s", version);
326 printk(KERN_INFO "%s: am79c961 found [%04lx, %d] ", dev->name, dev->base_addr, dev->irq);
327 request_region (dev->base_addr, 0x18, "am79c961");
329 /* Retrive and print the ethernet address. */
330 for (i = 0; i < 6; i++) {
331 dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff;
332 printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
335 if (am79c961_init(dev)) {
336 kfree (dev->priv);
337 dev->priv = NULL;
338 return -ENODEV;
341 dev->open = am79c961_open;
342 dev->stop = am79c961_close;
343 dev->hard_start_xmit = am79c961_sendpacket;
344 dev->get_stats = am79c961_getstats;
345 dev->set_multicast_list = am79c961_setmulticastlist;
347 /* Fill in the fields of the device structure with ethernet values. */
348 ether_setup(dev);
350 return 0;
354 am79c961_probe(struct net_device *dev)
356 static int initialised = 0;
358 if (initialised)
359 return -ENODEV;
360 initialised = 1;
362 dev->base_addr = 0x220;
363 dev->irq = 3;
365 return am79c961_probe1(dev);
369 * Open/initialize the board. This is called (in the current kernel)
370 * sometime after booting when the 'ifconfig' program is run.
372 * This routine should set everything up anew at each open, even
373 * registers that "should" only need to be set once at boot, so that
374 * there is non-reboot way to recover if something goes wrong.
376 static int
377 am79c961_open(struct net_device *dev)
379 struct dev_priv *priv = (struct dev_priv *)dev->priv;
381 MOD_INC_USE_COUNT;
383 memset (&priv->stats, 0, sizeof (priv->stats));
385 if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev))
386 return -EAGAIN;
388 am79c961_init_for_open(dev);
390 dev->tbusy = 0;
391 dev->interrupt = 0;
392 dev->start = 1;
393 return 0;
397 * The inverse routine to am79c961_open().
399 static int
400 am79c961_close(struct net_device *dev)
402 dev->tbusy = 1;
403 dev->start = 0;
405 am79c961_init(dev);
407 free_irq (dev->irq, dev);
409 MOD_DEC_USE_COUNT;
410 return 0;
414 * Get the current statistics. This may be called with the card open or
415 * closed.
417 static struct enet_statistics *am79c961_getstats (struct net_device *dev)
419 struct dev_priv *priv = (struct dev_priv *)dev->priv;
420 return &priv->stats;
424 * Set or clear promiscuous/multicast mode filter for this adaptor.
426 * We don't attempt any packet filtering. The card may have a SEEQ 8004
427 * in which does not have the other ethernet address registers present...
429 static void am79c961_setmulticastlist (struct net_device *dev)
431 unsigned long flags;
432 int i;
434 dev->flags &= ~IFF_ALLMULTI;
436 i = MODE_PORT0;
437 if (dev->flags & IFF_PROMISC)
438 i |= MODE_PROMISC;
440 save_flags_cli (flags);
441 write_rreg (dev->base_addr, MODE, i);
442 restore_flags (flags);
446 * Transmit a packet
448 static int
449 am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
451 struct dev_priv *priv = (struct dev_priv *)dev->priv;
453 if (!dev->tbusy) {
454 again:
455 if (!test_and_set_bit(0, (void*)&dev->tbusy)) {
456 unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
457 unsigned int hdraddr, bufaddr;
458 unsigned long flags;
460 hdraddr = priv->txhdr + (priv->txhead << 3);
461 bufaddr = priv->txbuffer[priv->txhead];
462 priv->txhead ++;
463 if (priv->txhead >= TX_BUFFERS)
464 priv->txhead = 0;
466 am_writebuffer (dev, bufaddr, skb->data, length);
467 am_writeword (dev, hdraddr + 4, -length);
468 am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
470 save_flags_cli (flags);
471 write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
472 dev->trans_start = jiffies;
473 restore_flags (flags);
475 if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
476 dev->tbusy = 0;
477 dev_kfree_skb (skb);
478 return 0;
479 } else
480 printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
481 return 1;
482 } else {
483 int tickssofar = jiffies - dev->trans_start;
484 if (tickssofar < 5)
485 return 1;
486 printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name);
487 /* Try to restart the adaptor. */
488 dev->tbusy = 0;
489 dev->trans_start = jiffies;
490 goto again;
494 static void
495 am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
497 struct net_device *dev = (struct net_device *)dev_id;
498 struct dev_priv *priv = (struct dev_priv *)dev->priv;
499 unsigned int status;
501 #if NET_DEBUG > 1
502 if(net_debug & DEBUG_INT)
503 printk(KERN_DEBUG "am79c961irq: %d ", irq);
504 #endif
506 dev->interrupt = 1;
508 status = read_rreg (dev->base_addr, CSR0);
509 write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
511 if (status & CSR0_RINT) /* Got a packet(s). */
512 am79c961_rx (dev, priv);
513 if (status & CSR0_TINT) /* Packets transmitted */
514 am79c961_tx (dev, priv);
515 if (status & CSR0_MISS)
516 priv->stats.rx_dropped ++;
518 dev->interrupt = 0;
520 #if NET_DEBUG > 1
521 if(net_debug & DEBUG_INT)
522 printk("done\n");
523 #endif
527 * If we have a good packet(s), get it/them out of the buffers.
529 static void
530 am79c961_rx(struct net_device *dev, struct dev_priv *priv)
532 unsigned long hdraddr;
533 unsigned long pktaddr;
535 do {
536 unsigned long status;
537 struct sk_buff *skb;
538 int len;
540 hdraddr = priv->rxhdr + (priv->rxtail << 3);
541 pktaddr = priv->rxbuffer[priv->rxtail];
543 status = am_readword (dev, hdraddr + 2);
544 if (status & RMD_OWN) /* do we own it? */
545 break;
547 priv->rxtail ++;
548 if (priv->rxtail >= RX_BUFFERS)
549 priv->rxtail = 0;
551 if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
552 am_writeword (dev, hdraddr + 2, RMD_OWN);
553 priv->stats.rx_errors ++;
554 if (status & RMD_ERR) {
555 if (status & RMD_FRAM)
556 priv->stats.rx_frame_errors ++;
557 if (status & RMD_CRC)
558 priv->stats.rx_crc_errors ++;
559 } else if (status & RMD_STP)
560 priv->stats.rx_length_errors ++;
561 continue;
564 len = am_readword (dev, hdraddr + 6);
565 skb = dev_alloc_skb (len + 2);
567 if (skb) {
568 unsigned char *buf;
570 skb->dev = dev;
571 skb_reserve (skb, 2);
572 buf = skb_put (skb, len);
574 am_readbuffer (dev, pktaddr, buf, len);
575 am_writeword (dev, hdraddr + 2, RMD_OWN);
576 skb->protocol = eth_type_trans(skb, dev);
577 netif_rx (skb);
578 priv->stats.rx_packets ++;
579 } else {
580 am_writeword (dev, hdraddr + 2, RMD_OWN);
581 printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
582 priv->stats.rx_dropped ++;
583 break;
585 } while (1);
589 * Update stats for the transmitted packet
591 static void
592 am79c961_tx(struct net_device *dev, struct dev_priv *priv)
594 do {
595 unsigned long hdraddr;
596 unsigned long status;
598 hdraddr = priv->txhdr + (priv->txtail << 3);
599 status = am_readword (dev, hdraddr + 2);
600 if (status & TMD_OWN)
601 break;
603 priv->txtail ++;
604 if (priv->txtail >= TX_BUFFERS)
605 priv->txtail = 0;
607 if (status & TMD_ERR) {
608 unsigned long status2;
610 priv->stats.tx_errors ++;
612 status2 = am_readword (dev, hdraddr + 6);
613 am_writeword (dev, hdraddr + 6, 0);
615 if (status2 & TST_RTRY)
616 priv->stats.collisions += 1;
617 if (status2 & TST_LCOL)
618 priv->stats.tx_window_errors ++;
619 if (status2 & TST_LCAR)
620 priv->stats.tx_carrier_errors ++;
621 if (status2 & TST_UFLO)
622 priv->stats.tx_fifo_errors ++;
623 continue;
625 priv->stats.tx_packets ++;
626 } while (priv->txtail != priv->txhead);
628 dev->tbusy = 0;
629 mark_bh (NET_BH);