|
|
1.1 root 1: /* we.c an wd8003 and wd8013 ethernet driver for linux. */
2: /*
3: Copyright (C) 1992 Ross Biro
4:
5: This program is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License as published by
7: the Free Software Foundation; either version 2, or (at your option)
8: any later version.
9:
10: This program is distributed in the hope that it will be useful,
11: but WITHOUT ANY WARRANTY; without even the implied warranty of
12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: GNU General Public License for more details.
14:
15: You should have received a copy of the GNU General Public License
16: along with this program; if not, write to the Free Software
17: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18:
19: The Author may be reached as [email protected] or
20: C/O Department of Mathematics; Stanford University; Stanford, CA 94305
21: */
22: /* The bsd386 version was used as an example in order to write this
23: code */
24:
25: /*
26: The driver was significantly modified by Bob Harris to allow the
27: software to operate with either the wd8003 or wd8013 boards. The
28: wd8013 boards will operate using full memory on board (as specified
29: by the user in Space.c) and the 16 bit wide interface. The driver
30: will autodetect which board it is using on boot (i.e. "using 16 bit I/F").
31: In addition, the interrupts structure was significantly modified to
32: respond to all the chips interrupts and to keep track of statistics.
33: The statistics are not currently used. Debug messages can be toggled
34: by setting the wd_debug variable to a non-zero number. The driver
35: can detect an open or shorted cable - the wd8013 board functions after
36: the problem is corrected, but the wd8003 board does not always recover.
37: The driver is gradually being migrated toward the National Semiconductor
38: recommendations. Constructive comments or suggestions can be sent to:
39:
40: Bob Harris, [email protected]
41: 7926 Jones Branch Drive, Suite 900
42: McLean, Va. 22102
43: */
44: /* Note: My driver was full of bugs. Basically if it works, credit
45: Bob Harris. If it's broken blame me. -RAB */
46:
47: #include <linux/config.h>
48: #include <linux/kernel.h>
49: #include <linux/sched.h>
50: #include <linux/fs.h>
51: #include <linux/tty.h>
52: #include <linux/types.h>
53: #include <linux/ptrace.h>
54: #include <asm/system.h>
55: #include <asm/segment.h>
56: #include <asm/io.h>
57: #include <asm/memory.h>
58: #include <errno.h>
59: #include <linux/fcntl.h>
60: #include <netinet/in.h>
61:
62: #include "dev.h"
63: #include "eth.h"
64: #include "timer.h"
65: #include "ip.h"
66: #include "tcp.h"
67: #include "sock.h"
68: #include "arp.h"
69:
70: #include "wereg.h"
71:
72: static unsigned char interrupt_mask;
73: /* format of status byte.
74: bit
75: 0 start
76: 1 open
77: 2 transmitter in use */
78:
79: #define START 1
80: #define OPEN 2
81: #define TRS_BUSY 0x400
82: #define IN_INT 8
83:
84: /* We need to get rid of all these statics and move them into the
85: device structure that way we can have more than one wd8003 board
86: in the system at once. */
87:
88: static volatile unsigned int status;
89:
90: static struct enet_statistics stats; /* Statistics collection */
91: static unsigned char max_pages; /* Board memory/256 */
92: static unsigned char wd_debug = 0; /* turns on/off debug messages */
93: static unsigned char dconfig = WD_DCONFIG; /* default data configuration */
94: static int tx_aborted = 0; /* Empties tx bit bucket */
95:
96: static int
97: max(int a, int b)
98: {
99: if (a>b) return (a);
100: return (b);
101: }
102:
103: static void
104: wd_start(struct device *dev)
105: {
106: unsigned char cmd;
107: interrupt_mask=RECV_MASK|TRANS_MASK;
108: cli();
109: cmd = inb_p(WD_COMM);
110: cmd &= ~(CSTOP|CPAGE);
111: cmd |= CSTART;
112: outb_p(cmd, WD_COMM);
113: outb_p(interrupt_mask,WD_IMR);
114: sti();
115: status |= START;
116: }
117:
118: int
119: wd8003_open(struct device *dev)
120: {
121: unsigned char cmd;
122: int i;
123: /* we probably don't want to be interrupted here. */
124: cli();
125: /* This section of code is mostly copied from the bsd driver which is
126: mostly copied from somewhere else. */
127: /* The somewhere else is probably the cmwymr(sp?) dos packet driver */
128:
129: cmd=inb_p(WD_COMM);
130: cmd|=CSTOP;
131: cmd &= ~(CSTART|CPAGE);
132: outb_p(cmd, WD_COMM);
133: outb_p(0, WD_IMR);
134: sti();
135: outb_p( dconfig,WD_DCR);
136: /*Zero the remote byte count. */
137: outb_p(0, WD_RBY0);
138: outb_p(0, WD_RBY1);
139: outb_p(WD_MCONFIG,WD_RCC);
140: outb_p(WD_TCONFIG,WD_TRC);
141: outb_p(0,WD_TRPG); /* Set the transmit page start = 0 */
142: outb_p( max_pages,WD_PSTOP); /* (read) page stop = top of board memory */
143: outb_p(WD_TXBS,WD_PSTRT); /* (read) page start = cur = bnd = top of tx memory */
144: outb_p(WD_TXBS,WD_BNDR);
145: /* clear interrupt status. */
146: outb_p(0xff,WD_ISR);
147: /* we don't want no stinking interrupts. */
148: outb_p(0 ,WD_IMR);
149: cmd|=1<<CPAGE_SHIFT;
150: outb_p(cmd,WD_COMM);
151: /* set the ether address. */
152: for (i=0; i < ETHER_ADDR_LEN; i++)
153: {
154: outb_p(dev->dev_addr[i],WD_PAR0+i);
155: }
156: /* National recommends setting the boundry < current page register */
157: outb_p(WD_TXBS+1,WD_CUR); /* Set the current page = page start + 1 */
158: /* set the multicast address. */
159: for (i=0; i < ETHER_ADDR_LEN; i++)
160: {
161: outb_p(dev->broadcast[i],WD_MAR0+i);
162: }
163:
164: cmd&=~(CPAGE|CRDMA);
165: cmd|= 4<<CRDMA_SHIFT;
166: outb_p(cmd, WD_COMM);
167: outb_p(WD_RCONFIG,WD_RCC);
168: status = OPEN;
169: wd_start(dev);
170: return (0);
171: }
172:
173: /* This routine just calls the ether rcv_int. */
174: static int
175: wdget(struct wd_ring *ring, struct device *dev)
176: {
177: unsigned char *fptr;
178: unsigned long len;
179: fptr = (unsigned char *)(ring +1);
180: len = ring->count-4;
181: return (dev_rint(fptr, len, 0, dev));
182: }
183:
184: int
185: wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
186: {
187: unsigned char cmd;
188: int len;
189: cli();
190: if (status & TRS_BUSY)
191: {
192: /* put in a time out. */
193: if (jiffies - dev->trans_start < 30)
194: return (1);
195: printk ("wd8003 transmit timed out. \n");
196: }
197: status |= TRS_BUSY;
198: sti();
199:
200: if (!skb->arp)
201: {
202: if ( dev->rebuild_header (skb+1, dev))
203: {
204: skb->dev = dev;
205: arp_queue (skb);
206: status &= ~TRS_BUSY;
207: return (0);
208: }
209: }
210:
211: memcpy ((unsigned char *)dev->mem_start, skb+1, skb->len);
212:
213: len = skb->len;
214:
215: /* now we need to set up the card info. */
216: dev->trans_start = jiffies;
217: len=max(len, ETHER_MIN_LEN); /* actually we should zero out
218: the extra memory. */
219: /* printk ("start_xmit len - %d\n", len);*/
220: cli();
221: cmd=inb_p(WD_COMM);
222: cmd &= ~CPAGE;
223: outb_p(cmd, WD_COMM);
224:
225: interrupt_mask |= TRANS_MASK;
226: if (!(status & IN_INT))
227: outb (interrupt_mask, WD_IMR);
228:
229: outb_p(len&0xff,WD_TB0);
230: outb_p(len>>8,WD_TB1);
231: cmd |= CTRANS;
232: outb_p(cmd,WD_COMM);
233: sti();
234:
235: if (skb->free)
236: {
237: free_skb (skb, FREE_WRITE);
238: }
239:
240: return (0);
241: }
242:
243: /* tell the card about the new boundary. */
244:
245: static void
246: wd_put_bnd(unsigned char bnd, struct device *dev )
247: {
248:
249: unsigned char cmd;
250:
251: /* Ensure page 0 selected */
252: cmd = inb_p( CR );
253: if (cmd & 0x40) {
254: outb_p(cmd & (~CPAGE1), WD_COMM); /* select page 0 */
255: outb_p(bnd, WD_BNDR);
256: outb_p(cmd | CPAGE1, WD_COMM); /* reselect page 1 */
257: } else {
258: outb_p(bnd, WD_BNDR);
259: }
260: }
261:
262: static unsigned char
263: wd_get_bnd( struct device *dev )
264: {
265:
266: unsigned char cmd, bnd;
267:
268: /* Ensure page 0 selected */
269: cmd = inb_p(WD_COMM);
270: if (cmd & 0x40) {
271: outb_p(cmd & (~CPAGE1), WD_COMM); /* select page 0 */
272: bnd = inb_p(WD_BNDR);
273: outb_p(cmd | CPAGE1, WD_COMM); /* reselect page 1 */
274: return (bnd);
275: } else {
276: return (inb_p(WD_BNDR));
277: }
278: }
279:
280: static unsigned char
281: wd_get_cur( struct device *dev )
282: {
283:
284: unsigned char cmd, cur;
285:
286: /* Ensure page 1 selected */
287: cmd = inb_p(WD_COMM);
288: if (cmd & 0x40) {
289: return (inb_p(WD_CUR));
290: } else {
291: outb_p(cmd | CPAGE1, WD_COMM); /* select page 1 */
292: cur = inb_p(WD_CUR);
293: outb_p(cmd & (~CPAGE1), WD_COMM); /* reselect page 0 */
294: return (cur);
295: }
296: }
297:
298: /* This routine handles the packet recieved interrupt. */
299: /* Debug routines slow things down, but reveal bugs... */
300: /* Modified Boundry Page Register to follow Current Page */
301:
302: static void
303: wd_rcv( struct device *dev )
304: {
305:
306: unsigned char pkt; /* Next packet page start */
307: unsigned char bnd; /* Last packet page end */
308: unsigned char cur; /* Future packet page start */
309: unsigned char cmd; /* Command register save */
310: struct wd_ring *ring;
311: int done=0;
312:
313: /* Calculate next packet location */
314: cur = wd_get_cur( dev );
315: bnd = wd_get_bnd( dev );
316: if( (pkt = bnd + 1) == max_pages )
317: pkt = WD_TXBS;
318:
319: while( done != 1)
320: {
321: if (pkt != cur)
322: {
323:
324: /* Position pointer to packet in card ring buffer */
325: ring = (struct wd_ring *) (dev->mem_start + (pkt << 8));
326:
327: /* Ensure a valid packet */
328: if( ring->status & 1 )
329: {
330: /* Too small and too big packets are
331: filtered by the board */
332: if( wd_debug )
333: printk("\nwd8013 - wdget: bnd = %d, pkt = %d, "
334: "cur = %d, status = %d, len = %d, next = %d",
335: bnd, pkt, cur, ring->status, ring->count,
336: ring->next);
337:
338: stats.rx_packets++; /* count all receives */
339: done = wdget( ring, dev ); /* get the packet */
340:
341: /* see if we need to process this packet again. */
342: if (done == -1) continue;
343:
344: /* Calculate next packet location */
345: pkt = ring->next;
346:
347: /* Compute new boundry - tell the chip */
348: if( (bnd = pkt - 1) < WD_TXBS )
349: bnd = max_pages - 1;
350: wd_put_bnd(bnd, dev);
351:
352: /* update our copy of cur. */
353: cur = wd_get_cur(dev);
354: }
355: else
356: { /* Bad packet in ring buffer -
357: should not happen due to hardware filtering */
358: printk("wd8013 - bad packet: len = %d, status = x%x, "
359: "bnd = %d, pkt = %d, cur = %d\n"
360: "trashing receive buffer!",
361: ring->count, ring->status, bnd, pkt,
362: cur);
363: /* Reset bnd = cur-1 */
364: if( ( bnd = wd_get_cur( dev ) - 1 ) < WD_TXBS )
365: bnd = max_pages - 1;
366: wd_put_bnd( bnd, dev );
367: break; /* return */
368: }
369:
370: }
371: else
372: {
373: done = dev_rint(NULL, 0,0, dev);
374: }
375: }
376:
377: /* reset to page 0 */
378: cmd = inb_p(WD_COMM);
379: if (cmd & 0x40)
380: {
381: outb_p(cmd & ~(CPAGE1), WD_COMM); /* select page 0 */
382: }
383: }
384:
385: /* This routine handles the interrupt case of receiver overruns */
386:
387: static void
388: wd_rx_over( struct device *dev )
389: {
390: unsigned char cmd, dummy;
391:
392: /* Nothing actually has been overwritten */
393: /* the chip has stopped at the boundry */
394: /* but we must get it going again - according to National Semiconductor */
395: printk ("wd_rx_over\n");
396: cmd = inb_p( CR ); /* get current command register */
397: cmd = (cmd&~(STA|PS0|PS1))|STOP; /* toggle start and stop bits, select page 0 */
398: outb_p( cmd, CR );
399: dummy = inb_p( RBCR0 ); /* required to detect reset status */
400: dummy = inb_p( RBCR1 );
401: wd_rcv( dev ); /* clear out received packets */
402:
403: if( inb_p( ISR ) & PRX )
404: outb_p( PRX, ISR ); /* acknowledge RX interrupt */
405: while( ( inb_p( ISR ) & RST ) == 0 ); /* wait for reset to be completed */
406: outb_p( RST, ISR ); /* acknowledge RST interrupt */
407: outb_p( (cmd&~STOP)|STA, CR ); /* Start NIC */
408: outb_p( WD_TCONFIG, TCR ); /* resume normal mode */
409: }
410:
411: /*
412: * This get's the transmit interrupts. It assumes command page 0 is set, and
413: * returns with command page 0 set.
414: */
415:
416: static void
417: wd_trs( struct device *dev )
418: {
419: unsigned char cmd, errors;
420: int len;
421:
422: if( wd_debug )
423: printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
424:
425: if( ( errors = inb_p( TSR ) & PTXOK ) || tx_aborted ){
426: if( (errors&~0x02) == 0 ){
427: stats.tx_packets++;
428: tx_aborted = 0;
429: }
430:
431: /* attempt to start a new transmission. */
432: len = dev_tint( (unsigned char *)dev->mem_start, dev );
433: if( len != 0 ){
434: len=max(len, ETHER_MIN_LEN);
435: cmd=inb_p(WD_COMM);
436: outb_p(len&0xff,WD_TB0);
437: outb_p(len>>8,WD_TB1);
438: cmd |= CTRANS;
439: outb_p(cmd,WD_COMM);
440: interrupt_mask |= TRANS_MASK;
441: }
442: else
443: {
444: status &= ~TRS_BUSY;
445: interrupt_mask &= ~TRANS_MASK;
446: return;
447: }
448: }
449: else{ /* TX error occurred! - H/W will reschedule */
450: if( errors & CRS ){
451: stats.tx_carrier_errors++;
452: printk("\nwd8013 - network cable short!");
453: }
454: if (errors & COL )
455: stats.collisions += inb_p( NCR );
456: if (errors & CDH )
457: stats.tx_heartbeat_errors++;
458: if (errors & OWC )
459: stats.tx_window_errors++;
460: }
461: }
462:
463: void
464: wd8003_interrupt(int reg_ptr)
465: {
466: unsigned char cmd;
467: unsigned char errors;
468: unsigned char isr;
469: struct device *dev;
470: struct pt_regs *ptr;
471: int irq;
472: int count = 0;
473:
474: ptr = (struct pt_regs *)reg_ptr;
475: irq = -(ptr->orig_eax+2);
476: for (dev = dev_base; dev != NULL; dev = dev->next)
477: {
478: if (dev->irq == irq) break;
479: }
480: if (dev == NULL)
481: {
482: printk ("we.c: irq %d for unknown device\n", irq);
483: return;
484: }
485: sti(); /* this could take a long time, we should have interrupts on. */
486:
487: cmd = inb_p( CR );/* Select page 0 */
488: if( cmd & (PS0|PS1 ) ){
489: cmd &= ~(PS0|PS1);
490: outb_p(cmd, CR );
491: }
492:
493: if (wd_debug)
494: printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
495:
496: status |= IN_INT;
497:
498: do{ /* find out who called */
499:
500: /* Check for overrunning receive buffer first */
501: if ( ( isr = inb_p( ISR ) ) & OVW ) { /* Receiver overwrite warning */
502: stats.rx_over_errors++;
503: if( wd_debug )
504: printk("\nwd8013 overrun bnd = %d, cur = %d", wd_get_bnd( dev ), wd_get_cur( dev ) );
505: wd_rx_over( dev ); /* performs wd_rcv() as well */
506: outb_p( OVW, ISR ); /* acknowledge interrupt */
507: }
508: else if ( isr & PRX ) { /* got a packet. */
509: wd_rcv( dev );
510: outb_p( PRX, ISR ); /* acknowledge interrupt */
511: }
512: /* This completes rx processing... whats next */
513:
514: if ( inb_p( ISR ) & PTX ) { /* finished sending a packet. */
515: wd_trs( dev );
516: outb_p( PTX, ISR ); /* acknowledge interrupt */
517: }
518:
519: if (inb_p( ISR ) & RXE ) { /* recieve error */
520: stats.rx_errors++; /* general errors */
521: errors = inb_p( RSR ); /* detailed errors */
522: if (errors & CRC )
523: stats.rx_crc_errors++;
524: if (errors & FAE )
525: stats.rx_frame_errors++;
526: if (errors & FO )
527: stats.rx_fifo_errors++;
528: if (errors & MPA )
529: stats.rx_missed_errors++;
530: outb_p( RXE, ISR ); /* acknowledge interrupt */
531: }
532:
533: if (inb_p( ISR ) & TXE ) { /* transmit aborted! */
534: stats.tx_errors++; /* general errors */
535: errors = inb_p( TSR ); /* get detailed errors */
536: if (errors & ABT ){
537: stats.tx_aborted_errors++;
538: printk("\nwd8013 - network cable open!");
539: }
540: if (errors & FU )
541: stats.tx_fifo_errors++;
542: printk("\nwd8013 - TX FIFO underrun!");
543:
544: /* Cannot do anymore - empty the bit bucket */
545: tx_aborted = 1;
546: wd_trs( dev );
547: tx_aborted = 0;
548:
549: outb_p( TXE, ISR ); /* acknowledge interrupt */
550: }
551:
552: if( inb_p( ISR ) & CNTE ){ /* Tally counters overflowing */
553: errors = inb_p( CNTR0 );
554: errors = inb_p( CNTR1 );
555: errors = inb_p( CNTR2 );
556: outb_p( CNTE, ISR ); /* acknowledge interrupt */
557: }
558: if( inb_p( ISR ) & RST ) /* Reset has been performed */
559: outb_p( RST, ISR ); /* acknowledge interrupt */
560:
561: if( wd_debug ){
562: if( ( isr = inb_p( ISR ) ) != 0 )
563: printk("\nwd8013 - ISR not cleared = x%x", isr );
564: }
565: if( ++count > max_pages + 1 ){
566: printk("\nwd8013_interrupt - infinite loop detected, isr = x%x, count = %d", isr, count );
567: }
568:
569: } while( inb_p( ISR ) != 0 );
570:
571: status &= ~IN_INT;
572: }
573:
574:
575: static struct sigaction wd8003_sigaction =
576: {
577: wd8003_interrupt,
578: 0,
579: 0,
580: NULL
581: };
582:
583: void
584: wd8003_init(struct device *dev)
585: {
586: unsigned char csum;
587: int i;
588: csum = 0;
589: for (i = 0; i < 8; i++)
590: {
591: csum += inb_p(WD_ROM+i);
592: }
593: if (csum != WD_CHECK)
594: {
595: printk ("Warning WD8013 board not found at i/o = %X.\n",dev->base_addr);
596:
597: /* make sure no one can attempt to open the device. */
598: status = OPEN;
599: return;
600: }
601: printk("wd8013");
602: /* initialize the rest of the device structure. */
603: dev->mtu = 1500; /* eth_mtu */
604: dev->hard_start_xmit = wd8003_start_xmit;
605: dev->open = wd8003_open;
606: dev->hard_header = eth_hard_header;
607: dev->add_arp = eth_add_arp;
608: dev->type_trans = eth_type_trans;
609: dev->hard_header_len = sizeof (struct enet_header);
610: dev->addr_len = ETHER_ADDR_LEN;
611: dev->type = ETHER_TYPE;
612: dev->queue_xmit = dev_queue_xmit;
613: dev->rebuild_header = eth_rebuild_header;
614: for (i = 0; i < DEV_NUMBUFFS; i++)
615: dev->buffs[i] = NULL;
616:
617: #ifndef FORCE_8BIT
618: /* check for 16 bit board - it doesn't have register 0/8 aliasing */
619: for (i = 0; i < 8; i++) {
620: if( inb_p( EN_SAPROM+i ) != inb_p( EN_CMD+i) ){
621: csum = inb_p( EN_REG1 ); /* fiddle with 16bit bit */
622: outb( csum ^ BUS16, EN_REG1 ); /* attempt to clear 16bit bit */
623: if( (csum & BUS16) == (inb_p( EN_REG1 ) & BUS16) ) {
624: printk(", using 16 bit I/F ");
625: dconfig |= 1; /* use word mode of operation */
626: outb_p( LAN16ENABLE|MEMMASK, EN_REG5);
627: outb( csum , EN_REG1 );
628: break; /* We have a 16bit board here! */
629: }
630: outb( csum , EN_REG1 );
631: }
632: }
633: #endif /* FORCE_8BIT */
634:
635: /* mapin the interface memory. */
636: outb_p(WD_IMEM,WD_CTL);
637:
638: /* clear the interface memory */
639: for (i = dev->mem_start; i < dev->mem_end; i++)
640: {
641: *((unsigned char *)i) = 0;
642: if (*((unsigned char *)i) != 0)
643: {
644: printk ("WD Memory error.\n");
645: if( (i - dev->mem_start) > 4096 )
646: break;
647: else
648: status = OPEN;
649: }
650: }
651: /* Calculate how many pages of memory on board */
652: max_pages = ( i - dev->mem_start )/256;
653:
654: /* need to set up the dev->mem_end and dev->rmem_end */
655: dev->rmem_end = i;
656: dev->mem_end = i;
657:
658: /* print the initialization message, and the
659: ethernet address. */
660: printk (", %d pages memory, ethernet Address: ", max_pages );
661: for (i = 0; i <ETHER_ADDR_LEN; i++)
662: {
663: dev->dev_addr[i]=inb_p(WD_ROM+i);
664: dev->broadcast[i]=0xff;
665: printk ("%2.2X ",dev->dev_addr[i]);
666: }
667:
668: /* Clear the statistics */
669: for( i = 0; i < sizeof( struct enet_statistics ); i++ )
670: ((char *)&stats)[i] = 0;
671:
672: printk ("\n");
673: status = 0;
674:
675: if (irqaction (dev->irq, &wd8003_sigaction))
676: {
677: printk ("Unable to get IRQ%d for wd8013 board\n", dev->irq);
678: }
679: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.