]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ether8390.c
kernel: cleanup the software mouse cursor mess
[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, (uchar*)KADDR(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, (uchar*)KADDR(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, (uchar*)KADDR(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
465         ctlr = ether->ctlr;
466
467         /*
468          * This routine is called both from the top level and from interrupt
469          * level and expects to be called with ctlr already locked.
470          */
471         if(ctlr->txbusy)
472                 return;
473         bp = qget(ether->oq);
474         if(bp == nil)
475                 return;
476
477         /*
478          * copy it to the card's memory by the appropriate means;
479          * start the transmission.
480          */
481         len = BLEN(bp);
482         if(ctlr->ram)
483                 memmove((uchar*)KADDR(ether->mem) + ctlr->tstart*Dp8390BufSz, bp->rp, len);
484         else
485                 dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, bp->rp, len);
486         freeb(bp);
487
488         regw(ctlr, Tbcr0, len & 0xFF);
489         regw(ctlr, Tbcr1, (len>>8) & 0xFF);
490         regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
491
492         ether->outpackets++;
493         ctlr->txbusy = 1;
494 }
495
496 static void
497 transmit(Ether* ether)
498 {
499         Dp8390 *ctlr;
500
501         ctlr = ether->ctlr;
502
503         ilock(ctlr);
504         txstart(ether);
505         iunlock(ctlr);
506 }
507
508 static void
509 overflow(Ether *ether)
510 {
511         Dp8390 *ctlr;
512         uchar txp;
513         int resend;
514
515         ctlr = ether->ctlr;
516
517         /*
518          * The following procedure is taken from the DP8390[12D] datasheet,
519          * it seems pretty adamant that this is what has to be done.
520          */
521         txp = regr(ctlr, Cr) & Txp;
522         regw(ctlr, Cr, Page0|RdABORT|Stp);
523         delay(2);
524         regw(ctlr, Rbcr0, 0);
525         regw(ctlr, Rbcr1, 0);
526
527         resend = 0;
528         if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0)
529                 resend = 1;
530
531         regw(ctlr, Tcr, LpbkNIC);
532         regw(ctlr, Cr, Page0|RdABORT|Sta);
533         receive(ether);
534         regw(ctlr, Isr, Ovw);
535         regw(ctlr, Tcr, LpbkNORMAL);
536
537         if(resend)
538                 regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
539 }
540
541 static void
542 interrupt(Ureg*, void* arg)
543 {
544         Ether *ether;
545         Dp8390 *ctlr;
546         uchar isr, r;
547
548         ether = arg;
549         ctlr = ether->ctlr;
550
551         /*
552          * While there is something of interest,
553          * clear all the interrupts and process.
554          */
555         ilock(ctlr);
556         regw(ctlr, Imr, 0x00);
557         while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){
558                 if(isr & Ovw){
559                         overflow(ether);
560                         regw(ctlr, Isr, Ovw);
561                         ether->overflows++;
562                 }
563
564                 /*
565                  * Packets have been received.
566                  * Take a spin round the ring.
567                  */
568                 if(isr & (Rxe|Prx)){
569                         receive(ether);
570                         regw(ctlr, Isr, Rxe|Prx);
571                 }
572
573                 /*
574                  * A packet completed transmission, successfully or
575                  * not. Start transmission on the next buffered packet,
576                  * and wake the output routine.
577                  */
578                 if(isr & (Txe|Ptx)){
579                         r = regr(ctlr, Tsr);
580                         if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){
581                                 print("dp8390: Tsr %#2.2ux", r);
582                                 ether->oerrs++;
583                         }
584
585                         regw(ctlr, Isr, Txe|Ptx);
586
587                         if(isr & Ptx)
588                                 ether->outpackets++;
589                         ctlr->txbusy = 0;
590                         txstart(ether);
591                 }
592
593                 if(isr & Cnt){
594                         ether->frames += regr(ctlr, Ref0);
595                         ether->crcs += regr(ctlr, Ref1);
596                         ether->buffs += regr(ctlr, Ref2);
597                         regw(ctlr, Isr, Cnt);
598                 }
599         }
600         regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
601         iunlock(ctlr);
602 }
603
604 static uchar allmar[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
605
606 static void
607 setfilter(Ether *ether, Dp8390 *ctlr)
608 {
609         uchar r, cr;
610         int i;
611         uchar *mar;
612
613         r = Ab;
614         mar = 0;
615         if(ether->prom){
616                 r |= Pro|Am;
617                 mar = allmar;
618         } else if(ether->nmaddr){
619                 r |= Am;
620                 mar = ctlr->mar;
621         }
622         if(mar){
623                 cr = regr(ctlr, Cr) & ~Txp;
624                 regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
625                 for(i = 0; i < 8; i++)
626                         regw(ctlr, Mar0+i, *(mar++));
627                 regw(ctlr, Cr, cr);
628         }
629         regw(ctlr, Rcr, r);
630 }
631
632 static void
633 promiscuous(void *arg, int )
634 {
635         Ether *ether;
636         Dp8390 *ctlr;
637
638         ether = arg;
639         ctlr = ether->ctlr;
640
641         ilock(ctlr);
642         setfilter(ether, ctlr);
643         iunlock(ctlr);
644 }
645
646 static void
647 setbit(Dp8390 *ctlr, int bit, int on)
648 {
649         int i, h;
650
651         i = bit/8;
652         h = bit%8;
653         if(on){
654                 if(++(ctlr->mref[bit]) == 1)
655                         ctlr->mar[i] |= 1<<h;
656         } else {
657                 if(--(ctlr->mref[bit]) <= 0){
658                         ctlr->mref[bit] = 0;
659                         ctlr->mar[i] &= ~(1<<h);
660                 }
661         }
662 }
663
664 static uchar reverse[64];
665
666 static void
667 multicast(void* arg, uchar *addr, int on)
668 {
669         Ether *ether;
670         Dp8390 *ctlr;
671         int i;
672         ulong h;
673
674         ether = arg;
675         ctlr = ether->ctlr;
676         if(reverse[1] == 0){
677                 for(i = 0; i < 64; i++)
678                         reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1)
679                                    | ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5);
680         }
681
682         /*
683          *  change filter bits
684          */
685         h = ethercrc(addr, 6);
686         ilock(ctlr);
687         setbit(ctlr, reverse[h&0x3f], on);
688         setfilter(ether, ctlr);
689         iunlock(ctlr);
690 }
691
692 static void
693 attach(Ether* ether)
694 {
695         Dp8390 *ctlr;
696         uchar r;
697
698         ctlr = ether->ctlr;
699
700         /*
701          * Enable the chip for transmit/receive.
702          * The init routine leaves the chip in monitor
703          * mode. Clear the missed-packet counter, it
704          * increments while in monitor mode.
705          * Sometimes there's an interrupt pending at this
706          * point but there's nothing in the Isr, so
707          * any pending interrupts are cleared and the
708          * mask of acceptable interrupts is enabled here.
709          */
710         r = Ab;
711         if(ether->prom)
712                 r |= Pro;
713         if(ether->nmaddr)
714                 r |= Am;
715         ilock(ctlr);
716         regw(ctlr, Isr, 0xFF);
717         regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
718         regw(ctlr, Rcr, r);
719         r = regr(ctlr, Ref2);
720         regw(ctlr, Tcr, LpbkNORMAL);
721         iunlock(ctlr);
722         USED(r);
723 }
724
725 static void
726 disable(Dp8390* ctlr)
727 {
728         int timo;
729
730         /*
731          * Stop the chip. Set the Stp bit and wait for the chip
732          * to finish whatever was on its tiny mind before it sets
733          * the Rst bit.
734          * The timeout is needed because there may not be a real
735          * chip there if this is called when probing for a device
736          * at boot.
737          */
738         regw(ctlr, Cr, Page0|RdABORT|Stp);
739         regw(ctlr, Rbcr0, 0);
740         regw(ctlr, Rbcr1, 0);
741         for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--)
742                         ;
743 }
744
745 int
746 dp8390reset(Ether* ether)
747 {
748         Dp8390 *ctlr;
749
750         ctlr = ether->ctlr;
751
752         /*
753          * This is the initialisation procedure described
754          * as 'mandatory' in the datasheet, with references
755          * to the 3C503 technical reference manual.
756          */ 
757         disable(ctlr);
758         if(ctlr->width != 1)
759                 regw(ctlr, Dcr, Ft4WORD|Ls|Wts);
760         else
761                 regw(ctlr, Dcr, Ft4WORD|Ls);
762
763         regw(ctlr, Rbcr0, 0);
764         regw(ctlr, Rbcr1, 0);
765
766         regw(ctlr, Tcr, LpbkNIC);
767         regw(ctlr, Rcr, Mon);
768
769         /*
770          * Init the ring hardware and software ring pointers.
771          * Can't initialise ethernet address as it may not be
772          * known yet.
773          */
774         ringinit(ctlr);
775         regw(ctlr, Tpsr, ctlr->tstart);
776
777         /*
778          * Clear any pending interrupts and mask then all off.
779          */
780         regw(ctlr, Isr, 0xFF);
781         regw(ctlr, Imr, 0);
782
783         /*
784          * Leave the chip initialised,
785          * but in monitor mode.
786          */
787         regw(ctlr, Cr, Page0|RdABORT|Sta);
788
789         /*
790          * Set up the software configuration.
791          */
792         ether->attach = attach;
793         ether->transmit = transmit;
794         ether->ifstat = 0;
795
796         ether->promiscuous = promiscuous;
797         ether->multicast = multicast;
798         ether->arg = ether;
799
800         intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
801
802         return 0;
803 }