This source file includes following definitions.
- max
- wd_start
- wd8003_open
- wdget
- wd8003_start_xmit
- wd_put_bnd
- wd_get_bnd
- wd_get_cur
- wd_rcv
- wd_rx_over
- wd_trs
- wd8003_interrupt
- wd8003_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 #include <linux/config.h>
79 #include <linux/kernel.h>
80 #include <linux/sched.h>
81 #include <linux/fs.h>
82 #include <linux/tty.h>
83 #include <linux/types.h>
84 #include <linux/ptrace.h>
85 #include <linux/string.h>
86 #include <asm/system.h>
87 #include <asm/segment.h>
88 #include <asm/io.h>
89 #include <errno.h>
90 #include <linux/fcntl.h>
91 #include <netinet/in.h>
92
93 #include "dev.h"
94 #include "eth.h"
95 #include "timer.h"
96 #include "ip.h"
97 #include "tcp.h"
98 #include "sock.h"
99 #include "arp.h"
100
101 #include "wereg.h"
102
103 static unsigned char interrupt_mask;
104
105
106
107
108
109
110 #define START 1
111 #define OPEN 2
112 #define TRS_BUSY 0x400
113 #define IN_INT 8
114
115
116
117
118
119 static volatile unsigned int status;
120
121 static struct enet_statistics stats;
122 static unsigned char max_pages;
123 static unsigned char wd_debug = 0;
124 static unsigned char dconfig = WD_DCONFIG;
125 static int tx_aborted = 0;
126
127 static void wd_trs (struct device *);
128
129 static int
130 max(int a, int b)
131 {
132 if (a>b) return (a);
133 return (b);
134 }
135
136 static void
137 wd_start(struct device *dev)
138 {
139 unsigned char cmd;
140 interrupt_mask=RECV_MASK|TRANS_MASK;
141 cli();
142 cmd = inb_p(WD_COMM);
143 cmd &= ~(CSTOP|CPAGE);
144 cmd |= CSTART;
145 outb_p(cmd, WD_COMM);
146 outb_p(interrupt_mask,WD_IMR);
147 sti();
148 status |= START;
149 }
150
151 int
152 wd8003_open(struct device *dev)
153 {
154 unsigned char cmd;
155 int i;
156
157 cli();
158
159
160
161
162 cmd=inb_p(WD_COMM);
163 cmd|=CSTOP;
164 cmd &= ~(CSTART|CPAGE);
165 outb_p(cmd, WD_COMM);
166 outb_p(0, WD_IMR);
167 sti();
168 outb_p( dconfig,WD_DCR);
169
170 outb_p(0, WD_RBY0);
171 outb_p(0, WD_RBY1);
172 outb_p(WD_MCONFIG,WD_RCC);
173 outb_p(WD_TCONFIG,WD_TRC);
174 outb_p(0,WD_TRPG);
175 outb_p( max_pages,WD_PSTOP);
176 outb_p(WD_TXBS,WD_PSTRT);
177 outb_p(WD_TXBS,WD_BNDR);
178
179 outb_p(0xff,WD_ISR);
180
181 outb_p(0 ,WD_IMR);
182 cmd|=1<<CPAGE_SHIFT;
183 outb_p(cmd,WD_COMM);
184
185 for (i=0; i < ETHER_ADDR_LEN; i++)
186 {
187 outb_p(dev->dev_addr[i],WD_PAR0+i);
188 }
189
190 outb_p(WD_TXBS+1,WD_CUR);
191
192 for (i=0; i < ETHER_ADDR_LEN; i++)
193 {
194 outb_p(dev->broadcast[i],WD_MAR0+i);
195 }
196
197 cmd&=~(CPAGE|CRDMA);
198 cmd|= 4<<CRDMA_SHIFT;
199 outb_p(cmd, WD_COMM);
200 outb_p(WD_RCONFIG,WD_RCC);
201 status = OPEN;
202 wd_start(dev);
203 return (0);
204 }
205
206
207 static int
208 wdget(volatile struct wd_ring *ring, struct device *dev)
209 {
210 unsigned char *fptr;
211 long len;
212 fptr = (unsigned char *)(ring +1);
213
214
215
216 len = ring->count-4;
217 if (len < 56)
218 printk ("we.c: Hardware problem, runt packet. ring->count = %d\n",
219 ring->count);
220 return (dev_rint(fptr, len, 0, dev));
221 }
222
223 int
224 wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
225 {
226 unsigned char cmd;
227 int len;
228
229 cli();
230 if (status & TRS_BUSY)
231 {
232
233 if (jiffies - dev->trans_start < 30)
234 {
235 return (1);
236 }
237
238 printk ("wd8003 transmit timed out. \n");
239 }
240 status |= TRS_BUSY;
241
242 if (skb == NULL)
243 {
244 sti();
245 wd_trs(dev);
246 return (0);
247 }
248
249
250 if (skb->dev != dev)
251 {
252 sti();
253 return (0);
254 }
255
256
257 if (!skb->arp)
258 {
259 if ( dev->rebuild_header (skb+1, dev))
260 {
261 cli();
262 if (skb->dev == dev)
263 {
264 arp_queue (skb);
265 }
266 cli ();
267 status &= ~TRS_BUSY;
268 sti();
269 return (0);
270 }
271 }
272
273 memcpy ((unsigned char *)dev->mem_start, skb+1, skb->len);
274
275 len = skb->len;
276
277
278 dev->trans_start = jiffies;
279 len=max(len, ETHER_MIN_LEN);
280
281
282
283 cmd=inb_p(WD_COMM);
284 cmd &= ~CPAGE;
285 outb_p(cmd, WD_COMM);
286
287 interrupt_mask |= TRANS_MASK;
288 if (!(status & IN_INT))
289 outb (interrupt_mask, WD_IMR);
290
291 outb_p(len&0xff,WD_TB0);
292 outb_p(len>>8,WD_TB1);
293 cmd |= CTRANS;
294 outb_p(cmd,WD_COMM);
295 sti();
296
297 if (skb->free)
298 {
299 kfree_skb (skb, FREE_WRITE);
300 }
301
302 return (0);
303 }
304
305
306
307 static void
308 wd_put_bnd(unsigned char bnd, struct device *dev )
309 {
310
311 unsigned char cmd;
312
313
314 cmd = inb_p( CR );
315 if (cmd & 0x40) {
316 outb_p(cmd & (~CPAGE1), WD_COMM);
317 outb_p(bnd, WD_BNDR);
318 outb_p(cmd | CPAGE1, WD_COMM);
319 } else {
320 outb_p(bnd, WD_BNDR);
321 }
322 }
323
324 static unsigned char
325 wd_get_bnd( struct device *dev )
326 {
327
328 unsigned char cmd, bnd;
329
330
331 cmd = inb_p(WD_COMM);
332 if (cmd & 0x40) {
333 outb_p(cmd & (~CPAGE1), WD_COMM);
334 bnd = inb_p(WD_BNDR);
335 outb_p(cmd | CPAGE1, WD_COMM);
336 return (bnd);
337 } else {
338 return (inb_p(WD_BNDR));
339 }
340 }
341
342 static unsigned char
343 wd_get_cur( struct device *dev )
344 {
345
346 unsigned char cmd, cur;
347
348
349 cmd = inb_p(WD_COMM);
350 if (cmd & 0x40) {
351 return (inb_p(WD_CUR));
352 } else {
353 outb_p(cmd | CPAGE1, WD_COMM);
354 cur = inb_p(WD_CUR);
355 outb_p(cmd & (~CPAGE1), WD_COMM);
356 return (cur);
357 }
358 }
359
360
361
362
363
364 static void
365 wd_rcv( struct device *dev )
366 {
367
368 unsigned char pkt;
369 unsigned char bnd;
370 unsigned char cur;
371 unsigned char cmd;
372 volatile struct wd_ring *ring;
373 int done=0;
374
375
376 cur = wd_get_cur( dev );
377 bnd = wd_get_bnd( dev );
378 if( (pkt = bnd + 1) == max_pages )
379 pkt = WD_TXBS;
380
381 while( done != 1)
382 {
383 if (pkt != cur)
384 {
385
386
387 ring = (volatile struct wd_ring *) (dev->mem_start + (pkt << 8));
388
389
390 if( ring->status & 1 )
391 {
392
393
394 if( wd_debug )
395 printk("\nwd8013 - wdget: bnd = %d, pkt = %d, "
396 "cur = %d, status = %d, len = %d, next = %d",
397 bnd, pkt, cur, ring->status, ring->count,
398 ring->next);
399
400 stats.rx_packets++;
401 done = wdget( ring, dev );
402
403
404 if (done == -1) continue;
405
406
407 pkt = ring->next;
408
409
410 if( (bnd = pkt - 1) < WD_TXBS )
411 bnd = max_pages - 1;
412 wd_put_bnd(bnd, dev);
413
414
415 cur = wd_get_cur(dev);
416 }
417 else
418 {
419
420 printk("wd8013 - bad packet: len = %d, status = x%x, "
421 "bnd = %d, pkt = %d, cur = %d\n"
422 "trashing receive buffer!",
423 ring->count, ring->status, bnd, pkt,
424 cur);
425
426 if( ( bnd = wd_get_cur( dev ) - 1 ) < WD_TXBS )
427 bnd = max_pages - 1;
428 wd_put_bnd( bnd, dev );
429 break;
430 }
431
432 }
433 else
434 {
435 done = dev_rint(NULL, 0,0, dev);
436 }
437 }
438
439
440 cmd = inb_p(WD_COMM);
441 if (cmd & 0x40)
442 {
443 outb_p(cmd & ~(CPAGE1), WD_COMM);
444 }
445 }
446
447
448
449 static void
450 wd_rx_over( struct device *dev )
451 {
452 unsigned char cmd, dummy;
453
454
455
456
457 printk ("wd_rx_over\n");
458 cmd = inb_p( CR );
459 cmd = (cmd&~(STA|PS0|PS1))|STOP;
460 outb_p( cmd, CR );
461 dummy = inb_p( RBCR0 );
462 dummy = inb_p( RBCR1 );
463 wd_rcv( dev );
464
465 if( inb_p( ISR ) & PRX )
466 outb_p( PRX, ISR );
467 while( ( inb_p( ISR ) & RST ) == 0 );
468 outb_p( RST, ISR );
469 outb_p( (cmd&~STOP)|STA, CR );
470 outb_p( WD_TCONFIG, TCR );
471 }
472
473
474
475
476
477
478 static void
479 wd_trs( struct device *dev )
480 {
481 unsigned char cmd, errors;
482 int len;
483
484 if( wd_debug )
485 printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
486
487 if( ( errors = inb_p( TSR ) & PTXOK ) || tx_aborted ){
488 if( (errors&~0x02) == 0 ){
489 stats.tx_packets++;
490 tx_aborted = 0;
491 }
492
493
494 len = dev_tint( (unsigned char *)dev->mem_start, dev );
495 if( len != 0 ){
496 len=max(len, ETHER_MIN_LEN);
497 cmd=inb_p(WD_COMM);
498 outb_p(len&0xff,WD_TB0);
499 outb_p(len>>8,WD_TB1);
500 cmd |= CTRANS;
501 outb_p(cmd,WD_COMM);
502 interrupt_mask |= TRANS_MASK;
503 }
504 else
505 {
506 status &= ~TRS_BUSY;
507 interrupt_mask &= ~TRANS_MASK;
508 return;
509 }
510 }
511 else{
512 if( errors & CRS ){
513 stats.tx_carrier_errors++;
514 printk("\nwd8013 - network cable short!");
515 }
516 if (errors & COL )
517 stats.collisions += inb_p( NCR );
518 if (errors & CDH )
519 stats.tx_heartbeat_errors++;
520 if (errors & OWC )
521 stats.tx_window_errors++;
522 }
523 }
524
525 void
526 wd8003_interrupt(int reg_ptr)
527 {
528 unsigned char cmd;
529 unsigned char errors;
530 unsigned char isr;
531 struct device *dev;
532 struct pt_regs *ptr;
533 int irq;
534 int count = 0;
535
536 ptr = (struct pt_regs *)reg_ptr;
537 irq = -(ptr->orig_eax+2);
538 for (dev = dev_base; dev != NULL; dev = dev->next)
539 {
540 if (dev->irq == irq) break;
541 }
542 if (dev == NULL)
543 {
544 printk ("we.c: irq %d for unknown device\n", irq);
545 return;
546 }
547 sti();
548
549 cmd = inb_p( CR );
550 if( cmd & (PS0|PS1 ) ){
551 cmd &= ~(PS0|PS1);
552 outb_p(cmd, CR );
553 }
554
555 if (wd_debug)
556 printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
557
558 status |= IN_INT;
559
560 do{
561 sti();
562
563 if ( ( isr = inb_p( ISR ) ) & OVW ) {
564 stats.rx_over_errors++;
565 if( wd_debug )
566 printk("\nwd8013 overrun bnd = %d, cur = %d", wd_get_bnd( dev ), wd_get_cur( dev ) );
567 wd_rx_over( dev );
568 outb_p( OVW, ISR );
569 }
570 else if ( isr & PRX ) {
571 wd_rcv( dev );
572 outb_p( PRX, ISR );
573 }
574
575
576 if ( inb_p( ISR ) & PTX ) {
577 wd_trs( dev );
578 outb_p( PTX, ISR );
579 }
580
581 if (inb_p( ISR ) & RXE ) {
582 stats.rx_errors++;
583 errors = inb_p( RSR );
584 if (errors & CRC )
585 stats.rx_crc_errors++;
586 if (errors & FAE )
587 stats.rx_frame_errors++;
588 if (errors & FO )
589 stats.rx_fifo_errors++;
590 if (errors & MPA )
591 stats.rx_missed_errors++;
592 outb_p( RXE, ISR );
593 }
594
595 if (inb_p( ISR ) & TXE ) {
596 stats.tx_errors++;
597 errors = inb_p( TSR );
598 if (errors & ABT ){
599 stats.tx_aborted_errors++;
600 printk("\nwd8013 - network cable open!");
601 }
602 if (errors & FU )
603 {
604 stats.tx_fifo_errors++;
605 printk("\nwd8013 - TX FIFO underrun!");
606 }
607
608
609 tx_aborted = 1;
610 wd_trs( dev );
611 tx_aborted = 0;
612
613 outb_p( TXE, ISR );
614 }
615
616 if( inb_p( ISR ) & CNTE ){
617 errors = inb_p( CNTR0 );
618 errors = inb_p( CNTR1 );
619 errors = inb_p( CNTR2 );
620 outb_p( CNTE, ISR );
621 }
622 if( inb_p( ISR ) & RST )
623 outb_p( RST, ISR );
624
625 if( wd_debug ){
626 if( ( isr = inb_p( ISR ) ) != 0 )
627 printk("\nwd8013 - ISR not cleared = x%x", isr );
628 }
629 if( ++count > max_pages + 1 ){
630 printk("\nwd8013_interrupt - infinite loop detected, isr = x%x, count = %d", isr, count );
631 }
632 cli();
633 } while( inb_p( ISR ) != 0 );
634
635 status &= ~IN_INT;
636 }
637
638
639 static struct sigaction wd8003_sigaction =
640 {
641 wd8003_interrupt,
642 0,
643 0,
644 NULL
645 };
646
647 int
648 wd8003_init(struct device *dev)
649 {
650 unsigned char csum;
651 int i;
652 csum = 0;
653 for (i = 0; i < 8; i++)
654 {
655 csum += inb_p(WD_ROM+i);
656 }
657 if (csum != WD_CHECK)
658 {
659 printk ("Warning WD8013 board not found at i/o = %X.\n",dev->base_addr);
660
661
662 status = OPEN;
663 return (1);
664 }
665 printk("wd8013");
666
667 dev->mtu = 1500;
668 dev->hard_start_xmit = wd8003_start_xmit;
669 dev->open = wd8003_open;
670 dev->hard_header = eth_hard_header;
671 dev->add_arp = eth_add_arp;
672 dev->type_trans = eth_type_trans;
673 dev->hard_header_len = sizeof (struct enet_header);
674 dev->addr_len = ETHER_ADDR_LEN;
675 dev->type = ETHER_TYPE;
676 dev->queue_xmit = dev_queue_xmit;
677 dev->rebuild_header = eth_rebuild_header;
678 for (i = 0; i < DEV_NUMBUFFS; i++)
679 dev->buffs[i] = NULL;
680
681 #ifndef FORCE_8BIT
682
683 for (i = 0; i < 8; i++) {
684 if( inb_p( EN_SAPROM+i ) != inb_p( EN_CMD+i) ){
685 csum = inb_p( EN_REG1 );
686 outb( csum ^ BUS16, EN_REG1 );
687 if( (csum & BUS16) == (inb_p( EN_REG1 ) & BUS16) ) {
688 printk(", using 16 bit I/F ");
689 dconfig |= 1;
690 outb_p( LAN16ENABLE|MEMMASK, EN_REG5);
691 outb( csum , EN_REG1 );
692 break;
693 }
694 outb( csum , EN_REG1 );
695 }
696 }
697 #endif
698
699
700 outb_p(WD_IMEM,WD_CTL);
701
702
703 for (i = dev->mem_start; i < dev->mem_end; i++)
704 {
705 *((unsigned char *)i) = 0;
706 if (*((unsigned char *)i) != 0)
707 {
708 printk ("WD Memory error.\n");
709 if( (i - dev->mem_start) > 4096 )
710 break;
711 else
712 status = OPEN;
713 }
714 }
715
716 max_pages = ( i - dev->mem_start )/256;
717
718
719 dev->rmem_end = i;
720 dev->mem_end = i;
721
722
723
724 printk (", %d pages memory, ethernet Address: ", max_pages );
725 for (i = 0; i <ETHER_ADDR_LEN; i++)
726 {
727 dev->dev_addr[i]=inb_p(WD_ROM+i);
728 dev->broadcast[i]=0xff;
729 printk ("%2.2X ",dev->dev_addr[i]);
730 }
731
732
733 for( i = 0; i < sizeof( struct enet_statistics ); i++ )
734 ((char *)&stats)[i] = 0;
735
736 printk ("\n");
737 status = 0;
738
739 if (irqaction (dev->irq, &wd8003_sigaction))
740 {
741 printk ("Unable to get IRQ%d for wd8013 board\n", dev->irq);
742 return (1);
743 }
744 return (0);
745 }