]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ether8390.c
usbehci: catch interrupt in tsleep
[plan9front.git] / sys / src / 9 / pc / ether8390.c
1 /*
2  * National Semiconductor DP8390 and clone
3  * Network Interface Controller.
4  */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "../port/error.h"
12 #include "../port/netif.h"
13 #include "../port/etherif.h"
14
15 #include "ether8390.h"
16
17 enum {                                  /* NIC core registers */
18         Cr              = 0x00,         /* command register, all pages */
19
20                                         /* Page 0, read */
21         Clda0           = 0x01,         /* current local DMA address 0 */
22         Clda1           = 0x02,         /* current local DMA address 1 */
23         Bnry            = 0x03,         /* boundary pointer (R/W) */
24         Tsr             = 0x04,         /* transmit status register */
25         Ncr             = 0x05,         /* number of collisions register */
26         Fifo            = 0x06,         /* FIFO */
27         Isr             = 0x07,         /* interrupt status register (R/W) */
28         Crda0           = 0x08,         /* current remote DMA address 0 */
29         Crda1           = 0x09,         /* current remote DMA address 1 */
30         Rsr             = 0x0C,         /* receive status register */
31         Ref0            = 0x0D,         /* frame alignment errors */
32         Ref1            = 0x0E,         /* CRC errors */
33         Ref2            = 0x0F,         /* missed packet errors */
34
35                                         /* Page 0, write */
36         Pstart          = 0x01,         /* page start register */
37         Pstop           = 0x02,         /* page stop register */
38         Tpsr            = 0x04,         /* transmit page start address */
39         Tbcr0           = 0x05,         /* transmit byte count register 0 */
40         Tbcr1           = 0x06,         /* transmit byte count register 1 */
41         Rsar0           = 0x08,         /* remote start address register 0 */
42         Rsar1           = 0x09,         /* remote start address register 1 */
43         Rbcr0           = 0x0A,         /* remote byte count register 0 */
44         Rbcr1           = 0x0B,         /* remote byte count register 1 */
45         Rcr             = 0x0C,         /* receive configuration register */
46         Tcr             = 0x0D,         /* transmit configuration register */
47         Dcr             = 0x0E,         /* data configuration register */
48         Imr             = 0x0F,         /* interrupt mask */
49
50                                         /* Page 1, read/write */
51         Par0            = 0x01,         /* physical address register 0 */
52         Curr            = 0x07,         /* current page register */
53         Mar0            = 0x08,         /* multicast address register 0 */
54 };
55
56 enum {                                  /* Cr */
57         Stp             = 0x01,         /* stop */
58         Sta             = 0x02,         /* start */
59         Txp             = 0x04,         /* transmit packet */
60         Rd0             = 0x08,         /* remote DMA command */
61         Rd1             = 0x10, 
62         Rd2             = 0x20,
63         RdREAD          = Rd0,          /* remote read */
64         RdWRITE         = Rd1,          /* remote write */
65         RdSEND          = Rd1|Rd0,      /* send packet */
66         RdABORT         = Rd2,          /* abort/complete remote DMA */
67         Ps0             = 0x40,         /* page select */
68         Ps1             = 0x80,
69         Page0           = 0x00,
70         Page1           = Ps0,
71         Page2           = Ps1,
72 };
73
74 enum {                                  /* Isr/Imr */
75         Prx             = 0x01,         /* packet received */
76         Ptx             = 0x02,         /* packet transmitted */
77         Rxe             = 0x04,         /* receive error */
78         Txe             = 0x08,         /* transmit error */
79         Ovw             = 0x10,         /* overwrite warning */
80         Cnt             = 0x20,         /* counter overflow */
81         Rdc             = 0x40,         /* remote DMA complete */
82         Rst             = 0x80,         /* reset status */
83 };
84
85 enum {                                  /* Dcr */
86         Wts             = 0x01,         /* word transfer select */
87         Bos             = 0x02,         /* byte order select */
88         Las             = 0x04,         /* long address select */
89         Ls              = 0x08,         /* loopback select */
90         Arm             = 0x10,         /* auto-initialise remote */
91         Ft0             = 0x20,         /* FIFO threshold select */
92         Ft1             = 0x40,
93         Ft1WORD         = 0x00,
94         Ft2WORD         = Ft0,
95         Ft4WORD         = Ft1,
96         Ft6WORD         = Ft1|Ft0,
97 };
98
99 enum {                                  /* Tcr */
100         Crc             = 0x01,         /* inhibit CRC */
101         Lb0             = 0x02,         /* encoded loopback control */
102         Lb1             = 0x04,
103         LpbkNORMAL      = 0x00,         /* normal operation */
104         LpbkNIC         = Lb0,          /* internal NIC module loopback */
105         LpbkENDEC       = Lb1,          /* internal ENDEC module loopback */
106         LpbkEXTERNAL    = Lb1|Lb0,      /* external loopback */
107         Atd             = 0x08,         /* auto transmit disable */
108         Ofst            = 0x10,         /* collision offset enable */
109 };
110
111 enum {                                  /* Tsr */
112         Ptxok           = 0x01,         /* packet transmitted */
113         Col             = 0x04,         /* transmit collided */
114         Abt             = 0x08,         /* tranmit aborted */
115         Crs             = 0x10,         /* carrier sense lost */
116         Fu              = 0x20,         /* FIFO underrun */
117         Cdh             = 0x40,         /* CD heartbeat */
118         Owc             = 0x80,         /* out of window collision */
119 };
120
121 enum {                                  /* Rcr */
122         Sep             = 0x01,         /* save errored packets */
123         Ar              = 0x02,         /* accept runt packets */
124         Ab              = 0x04,         /* accept broadcast */
125         Am              = 0x08,         /* accept multicast */
126         Pro             = 0x10,         /* promiscuous physical */
127         Mon             = 0x20,         /* monitor mode */
128 };
129
130 enum {                                  /* Rsr */
131         Prxok           = 0x01,         /* packet received intact */
132         Crce            = 0x02,         /* CRC error */
133         Fae             = 0x04,         /* frame alignment error */
134         Fo              = 0x08,         /* FIFO overrun */
135         Mpa             = 0x10,         /* missed packet */
136         Phy             = 0x20,         /* physical/multicast address */
137         Dis             = 0x40,         /* receiver disabled */
138         Dfr             = 0x80,         /* deferring */
139 };
140
141 typedef struct Hdr Hdr;
142 struct Hdr {
143         uchar   status;
144         uchar   next;
145         uchar   len0;
146         uchar   len1;
147 };
148
149 void
150 dp8390getea(Ether* ether, uchar* ea)
151 {
152         Dp8390 *ctlr;
153         uchar cr;
154         int i;
155
156         ctlr = ether->ctlr;
157
158         /*
159          * Get the ethernet address from the chip.
160          * Take care to restore the command register
161          * afterwards.
162          */
163         ilock(ctlr);
164         cr = regr(ctlr, Cr) & ~Txp;
165         regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
166         for(i = 0; i < Eaddrlen; i++)
167                 ea[i] = regr(ctlr, Par0+i);
168         regw(ctlr, Cr, cr);
169         iunlock(ctlr);
170 }
171
172 void
173 dp8390setea(Ether* ether)
174 {
175         int i;
176         uchar cr;
177         Dp8390 *ctlr;
178
179         ctlr = ether->ctlr;
180
181         /*
182          * Set the ethernet address into the chip.
183          * Take care to restore the command register
184          * afterwards. Don't care about multicast
185          * addresses as multicast is never enabled
186          * (currently).
187          */
188         ilock(ctlr);
189         cr = regr(ctlr, Cr) & ~Txp;
190         regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
191         for(i = 0; i < Eaddrlen; i++)
192                 regw(ctlr, Par0+i, ether->ea[i]);
193         regw(ctlr, Cr, cr);
194         iunlock(ctlr);
195 }
196
197 static void*
198 _dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
199 {
200         uchar cr;
201         int timo;
202
203         /*
204          * Read some data at offset 'from' in the card's memory
205          * using the DP8390 remote DMA facility, and place it at
206          * 'to' in main memory, via the I/O data port.
207          */
208         cr = regr(ctlr, Cr) & ~Txp;
209         regw(ctlr, Cr, Page0|RdABORT|Sta);
210         regw(ctlr, Isr, Rdc);
211
212         /*
213          * Set up the remote DMA address and count.
214          */
215         len = ROUNDUP(len, ctlr->width);
216         regw(ctlr, Rbcr0, len & 0xFF);
217         regw(ctlr, Rbcr1, (len>>8) & 0xFF);
218         regw(ctlr, Rsar0, from & 0xFF);
219         regw(ctlr, Rsar1, (from>>8) & 0xFF);
220
221         /*
222          * Start the remote DMA read and suck the data
223          * out of the I/O port.
224          */
225         regw(ctlr, Cr, Page0|RdREAD|Sta);
226         rdread(ctlr, to, len);
227
228         /*
229          * Wait for the remote DMA to complete. The timeout
230          * is necessary because this routine may be called on
231          * a non-existent chip during initialisation and, due
232          * to the miracles of the bus, it's possible to get this
233          * far and still be talking to a slot full of nothing.
234          */
235         for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
236                         ;
237
238         regw(ctlr, Isr, Rdc);
239         regw(ctlr, Cr, cr);
240
241         return to;
242 }
243
244 void*
245 dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
246 {
247         void *v;
248
249         ilock(ctlr);
250         v = _dp8390read(ctlr, to, from, len);
251         iunlock(ctlr);
252
253         return v;
254 }
255
256 static void*
257 dp8390write(Dp8390* ctlr, ulong to, void* from, ulong len)
258 {
259         ulong crda;
260         uchar cr;
261         int timo, width;
262
263 top:
264         /*
265          * Write some data to offset 'to' in the card's memory
266          * using the DP8390 remote DMA facility, reading it at
267          * 'from' in main memory, via the I/O data port.
268          */
269         cr = regr(ctlr, Cr) & ~Txp;
270         regw(ctlr, Cr, Page0|RdABORT|Sta);
271         regw(ctlr, Isr, Rdc);
272
273         len = ROUNDUP(len, ctlr->width);
274
275         /*
276          * Set up the remote DMA address and count.
277          * This is straight from the DP8390[12D] datasheet,
278          * hence the initial set up for read.
279          * Assumption here that the A7000 EtherV card will
280          * never need a dummyrr.
281          */
282         if(ctlr->dummyrr && (ctlr->width == 1 || ctlr->width == 2)){
283                 if(ctlr->width == 2)
284                         width = 1;
285                 else
286                         width = 0;
287                 crda = to-1-width;
288                 regw(ctlr, Rbcr0, (len+1+width) & 0xFF);
289                 regw(ctlr, Rbcr1, ((len+1+width)>>8) & 0xFF);
290                 regw(ctlr, Rsar0, crda & 0xFF);
291                 regw(ctlr, Rsar1, (crda>>8) & 0xFF);
292                 regw(ctlr, Cr, Page0|RdREAD|Sta);
293         
294                 for(timo=0;; timo++){
295                         if(timo > 10000){
296                                 print("ether8390: dummyrr timeout; assuming nodummyrr\n");
297                                 ctlr->dummyrr = 0;
298                                 goto top;
299                         }
300                         crda = regr(ctlr, Crda0);
301                         crda |= regr(ctlr, Crda1)<<8;
302                         if(crda == to){
303                                 /*
304                                  * Start the remote DMA write and make sure
305                                  * the registers are correct.
306                                  */
307                                 regw(ctlr, Cr, Page0|RdWRITE|Sta);
308         
309                                 crda = regr(ctlr, Crda0);
310                                 crda |= regr(ctlr, Crda1)<<8;
311                                 if(crda != to)
312                                         panic("crda write %lud to %lud", crda, to);
313         
314                                 break;
315                         }
316                 }
317         }
318         else{
319                 regw(ctlr, Rsar0, to & 0xFF);
320                 regw(ctlr, Rsar1, (to>>8) & 0xFF);
321                 regw(ctlr, Rbcr0, len & 0xFF);
322                 regw(ctlr, Rbcr1, (len>>8) & 0xFF);
323                 regw(ctlr, Cr, Page0|RdWRITE|Sta);
324         }
325
326         /*
327          * Pump the data into the I/O port
328          * then wait for the remote DMA to finish.
329          */
330         rdwrite(ctlr, from, len);
331         for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
332                         ;
333
334         regw(ctlr, Isr, Rdc);
335         regw(ctlr, Cr, cr);
336
337         return (void*)to;
338 }
339
340 static void
341 ringinit(Dp8390* ctlr)
342 {
343         regw(ctlr, Pstart, ctlr->pstart);
344         regw(ctlr, Pstop, ctlr->pstop);
345         regw(ctlr, Bnry, ctlr->pstop-1);
346
347         regw(ctlr, Cr, Page1|RdABORT|Stp);
348         regw(ctlr, Curr, ctlr->pstart);
349         regw(ctlr, Cr, Page0|RdABORT|Stp);
350
351         ctlr->nxtpkt = ctlr->pstart;
352 }
353
354 static uchar
355 getcurr(Dp8390* ctlr)
356 {
357         uchar cr, curr;
358
359         cr = regr(ctlr, Cr) & ~Txp;
360         regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
361         curr = regr(ctlr, Curr);
362         regw(ctlr, Cr, cr);
363
364         return curr;
365 }
366
367 static void
368 receive(Ether* ether)
369 {
370         Dp8390 *ctlr;
371         uchar curr, *p;
372         Hdr hdr;
373         ulong count, data, len;
374         Block *bp;
375
376         ctlr = ether->ctlr;
377         for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){
378                 data = ctlr->nxtpkt*Dp8390BufSz;
379                 if(ctlr->ram)
380                         memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr));
381                 else
382                         _dp8390read(ctlr, &hdr, data, sizeof(Hdr));
383
384                 /*
385                  * Don't believe the upper byte count, work it
386                  * out from the software next-page pointer and
387                  * the current next-page pointer.
388                  */
389                 if(hdr.next > ctlr->nxtpkt)
390                         len = hdr.next - ctlr->nxtpkt - 1;
391                 else
392                         len = (ctlr->pstop-ctlr->nxtpkt) + (hdr.next-ctlr->pstart) - 1;
393                 if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
394                         len--;
395
396                 len = ((len<<8)|hdr.len0)-4;
397
398                 /*
399                  * Chip is badly scrogged, reinitialise the ring.
400                  */
401                 if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop
402                   || len < 60 || len > sizeof(Etherpkt)){
403                         print("dp8390: H%2.2ux+%2.2ux+%2.2ux+%2.2ux,%lud\n",
404                                 hdr.status, hdr.next, hdr.len0, hdr.len1, len);
405                         regw(ctlr, Cr, Page0|RdABORT|Stp);
406                         ringinit(ctlr);
407                         regw(ctlr, Cr, Page0|RdABORT|Sta);
408
409                         return;
410                 }
411
412                 /*
413                  * If it's a good packet read it in to the software buffer.
414                  * If the packet wraps round the hardware ring, read it in
415                  * two pieces.
416                  */
417                 if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && (bp = iallocb(len))){
418                         p = bp->rp;
419                         bp->wp = p+len;
420                         data += sizeof(Hdr);
421
422                         if((data+len) >= ctlr->pstop*Dp8390BufSz){
423                                 count = ctlr->pstop*Dp8390BufSz - data;
424                                 if(ctlr->ram)
425                                         memmove(p, (void*)(ether->mem+data), count);
426                                 else
427                                         _dp8390read(ctlr, p, data, count);
428                                 p += count;
429                                 data = ctlr->pstart*Dp8390BufSz;
430                                 len -= count;
431                         }
432                         if(len){
433                                 if(ctlr->ram)
434                                         memmove(p, (void*)(ether->mem+data), len);
435                                 else
436                                         _dp8390read(ctlr, p, data, len);
437                         }
438
439                         /*
440                          * Copy the packet to whoever wants it.
441                          */
442                         etheriq(ether, bp);
443                 }
444
445                 /*
446                  * Finished with this packet, update the
447                  * hardware and software ring pointers.
448                  */
449                 ctlr->nxtpkt = hdr.next;
450
451                 hdr.next--;
452                 if(hdr.next < ctlr->pstart)
453                         hdr.next = ctlr->pstop-1;
454                 regw(ctlr, Bnry, hdr.next);
455         }
456 }
457
458 static void
459 txstart(Ether* ether)
460 {
461         int len;
462         Dp8390 *ctlr;
463         Block *bp;
464         uchar minpkt[ETHERMINTU], *rp;
465
466         ctlr = ether->ctlr;
467
468         /*
469          * This routine is called both from the top level and from interrupt
470          * level and expects to be called with ctlr already locked.
471          */
472         if(ctlr->txbusy)
473                 return;
474         bp = qget(ether->oq);
475         if(bp == nil)
476                 return;
477
478         /*
479          * Make sure the packet is of minimum length;
480          * copy it to the card's memory by the appropriate means;
481          * start the transmission.
482          */
483         len = BLEN(bp);
484         rp = bp->rp;
485         if(len < ETHERMINTU){
486                 rp = minpkt;
487                 memmove(rp, bp->rp, len);
488                 memset(rp+len, 0, ETHERMINTU-len);
489                 len = ETHERMINTU;
490         }
491
492         if(ctlr->ram)
493                 memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len);
494         else
495                 dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len);
496         freeb(bp);
497
498         regw(ctlr, Tbcr0, len & 0xFF);
499         regw(ctlr, Tbcr1, (len>>8) & 0xFF);
500         regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
501
502         ether->outpackets++;
503         ctlr->txbusy = 1;
504 }
505
506 static void
507 transmit(Ether* ether)
508 {
509         Dp8390 *ctlr;
510
511         ctlr = ether->ctlr;
512
513         ilock(ctlr);
514         txstart(ether);
515         iunlock(ctlr);
516 }
517
518 static void
519 overflow(Ether *ether)
520 {
521         Dp8390 *ctlr;
522         uchar txp;
523         int resend;
524
525         ctlr = ether->ctlr;
526
527         /*
528          * The following procedure is taken from the DP8390[12D] datasheet,
529          * it seems pretty adamant that this is what has to be done.
530          */
531         txp = regr(ctlr, Cr) & Txp;
532         regw(ctlr, Cr, Page0|RdABORT|Stp);
533         delay(2);
534         regw(ctlr, Rbcr0, 0);
535         regw(ctlr, Rbcr1, 0);
536
537         resend = 0;
538         if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0)
539                 resend = 1;
540
541         regw(ctlr, Tcr, LpbkNIC);
542         regw(ctlr, Cr, Page0|RdABORT|Sta);
543         receive(ether);
544         regw(ctlr, Isr, Ovw);
545         regw(ctlr, Tcr, LpbkNORMAL);
546
547         if(resend)
548                 regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
549 }
550
551 static void
552 interrupt(Ureg*, void* arg)
553 {
554         Ether *ether;
555         Dp8390 *ctlr;
556         uchar isr, r;
557
558         ether = arg;
559         ctlr = ether->ctlr;
560
561         /*
562          * While there is something of interest,
563          * clear all the interrupts and process.
564          */
565         ilock(ctlr);
566         regw(ctlr, Imr, 0x00);
567         while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){
568                 if(isr & Ovw){
569                         overflow(ether);
570                         regw(ctlr, Isr, Ovw);
571                         ether->overflows++;
572                 }
573
574                 /*
575                  * Packets have been received.
576                  * Take a spin round the ring.
577                  */
578                 if(isr & (Rxe|Prx)){
579                         receive(ether);
580                         regw(ctlr, Isr, Rxe|Prx);
581                 }
582
583                 /*
584                  * A packet completed transmission, successfully or
585                  * not. Start transmission on the next buffered packet,
586                  * and wake the output routine.
587                  */
588                 if(isr & (Txe|Ptx)){
589                         r = regr(ctlr, Tsr);
590                         if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){
591                                 print("dp8390: Tsr %#2.2ux", r);
592                                 ether->oerrs++;
593                         }
594
595                         regw(ctlr, Isr, Txe|Ptx);
596
597                         if(isr & Ptx)
598                                 ether->outpackets++;
599                         ctlr->txbusy = 0;
600                         txstart(ether);
601                 }
602
603                 if(isr & Cnt){
604                         ether->frames += regr(ctlr, Ref0);
605                         ether->crcs += regr(ctlr, Ref1);
606                         ether->buffs += regr(ctlr, Ref2);
607                         regw(ctlr, Isr, Cnt);
608                 }
609         }
610         regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
611         iunlock(ctlr);
612 }
613
614 static uchar allmar[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
615
616 static void
617 setfilter(Ether *ether, Dp8390 *ctlr)
618 {
619         uchar r, cr;
620         int i;
621         uchar *mar;
622
623         r = Ab;
624         mar = 0;
625         if(ether->prom){
626                 r |= Pro|Am;
627                 mar = allmar;
628         } else if(ether->nmaddr){
629                 r |= Am;
630                 mar = ctlr->mar;
631         }
632         if(mar){
633                 cr = regr(ctlr, Cr) & ~Txp;
634                 regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
635                 for(i = 0; i < 8; i++)
636                         regw(ctlr, Mar0+i, *(mar++));
637                 regw(ctlr, Cr, cr);
638         }
639         regw(ctlr, Rcr, r);
640 }
641
642 static void
643 promiscuous(void *arg, int )
644 {
645         Ether *ether;
646         Dp8390 *ctlr;
647
648         ether = arg;
649         ctlr = ether->ctlr;
650
651         ilock(ctlr);
652         setfilter(ether, ctlr);
653         iunlock(ctlr);
654 }
655
656 static void
657 setbit(Dp8390 *ctlr, int bit, int on)
658 {
659         int i, h;
660
661         i = bit/8;
662         h = bit%8;
663         if(on){
664                 if(++(ctlr->mref[bit]) == 1)
665                         ctlr->mar[i] |= 1<<h;
666         } else {
667                 if(--(ctlr->mref[bit]) <= 0){
668                         ctlr->mref[bit] = 0;
669                         ctlr->mar[i] &= ~(1<<h);
670                 }
671         }
672 }
673
674 static uchar reverse[64];
675
676 static void
677 multicast(void* arg, uchar *addr, int on)
678 {
679         Ether *ether;
680         Dp8390 *ctlr;
681         int i;
682         ulong h;
683
684         ether = arg;
685         ctlr = ether->ctlr;
686         if(reverse[1] == 0){
687                 for(i = 0; i < 64; i++)
688                         reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1)
689                                    | ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5);
690         }
691
692         /*
693          *  change filter bits
694          */
695         h = ethercrc(addr, 6);
696         ilock(ctlr);
697         setbit(ctlr, reverse[h&0x3f], on);
698         setfilter(ether, ctlr);
699         iunlock(ctlr);
700 }
701
702 static void
703 attach(Ether* ether)
704 {
705         Dp8390 *ctlr;
706         uchar r;
707
708         ctlr = ether->ctlr;
709
710         /*
711          * Enable the chip for transmit/receive.
712          * The init routine leaves the chip in monitor
713          * mode. Clear the missed-packet counter, it
714          * increments while in monitor mode.
715          * Sometimes there's an interrupt pending at this
716          * point but there's nothing in the Isr, so
717          * any pending interrupts are cleared and the
718          * mask of acceptable interrupts is enabled here.
719          */
720         r = Ab;
721         if(ether->prom)
722                 r |= Pro;
723         if(ether->nmaddr)
724                 r |= Am;
725         ilock(ctlr);
726         regw(ctlr, Isr, 0xFF);
727         regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
728         regw(ctlr, Rcr, r);
729         r = regr(ctlr, Ref2);
730         regw(ctlr, Tcr, LpbkNORMAL);
731         iunlock(ctlr);
732         USED(r);
733 }
734
735 static void
736 disable(Dp8390* ctlr)
737 {
738         int timo;
739
740         /*
741          * Stop the chip. Set the Stp bit and wait for the chip
742          * to finish whatever was on its tiny mind before it sets
743          * the Rst bit.
744          * The timeout is needed because there may not be a real
745          * chip there if this is called when probing for a device
746          * at boot.
747          */
748         regw(ctlr, Cr, Page0|RdABORT|Stp);
749         regw(ctlr, Rbcr0, 0);
750         regw(ctlr, Rbcr1, 0);
751         for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--)
752                         ;
753 }
754
755 int
756 dp8390reset(Ether* ether)
757 {
758         Dp8390 *ctlr;
759
760         ctlr = ether->ctlr;
761
762         /*
763          * This is the initialisation procedure described
764          * as 'mandatory' in the datasheet, with references
765          * to the 3C503 technical reference manual.
766          */ 
767         disable(ctlr);
768         if(ctlr->width != 1)
769                 regw(ctlr, Dcr, Ft4WORD|Ls|Wts);
770         else
771                 regw(ctlr, Dcr, Ft4WORD|Ls);
772
773         regw(ctlr, Rbcr0, 0);
774         regw(ctlr, Rbcr1, 0);
775
776         regw(ctlr, Tcr, LpbkNIC);
777         regw(ctlr, Rcr, Mon);
778
779         /*
780          * Init the ring hardware and software ring pointers.
781          * Can't initialise ethernet address as it may not be
782          * known yet.
783          */
784         ringinit(ctlr);
785         regw(ctlr, Tpsr, ctlr->tstart);
786
787         /*
788          * Clear any pending interrupts and mask then all off.
789          */
790         regw(ctlr, Isr, 0xFF);
791         regw(ctlr, Imr, 0);
792
793         /*
794          * Leave the chip initialised,
795          * but in monitor mode.
796          */
797         regw(ctlr, Cr, Page0|RdABORT|Sta);
798
799         /*
800          * Set up the software configuration.
801          */
802         ether->attach = attach;
803         ether->transmit = transmit;
804         ether->ifstat = 0;
805
806         ether->promiscuous = promiscuous;
807         ether->multicast = multicast;
808         ether->arg = ether;
809
810         intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
811
812         return 0;
813 }