]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ether83815.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / 9 / pc / ether83815.c
1 /*
2  * National Semiconductor DP83815
3  *
4  * Supports only internal PHY and has been tested on:
5  *      Netgear FA311TX (using Netgear DS108 10/100 hub)
6  *      SiS 900 within SiS 630
7  * To do:
8  *      check Ethernet address;
9  *      test autonegotiation on 10 Mbit, and 100 Mbit full duplex;
10  *      external PHY via MII (should be common code for MII);
11  *      thresholds;
12  *      ring sizing;
13  *      physical link changes/disconnect;
14  *      push initialisation back to attach.
15  *
16  * C H Forsyth, forsyth@vitanuova.com, 18th June 2001.
17  */
18
19 #include "u.h"
20 #include "../port/lib.h"
21 #include "mem.h"
22 #include "dat.h"
23 #include "fns.h"
24 #include "io.h"
25 #include "../port/error.h"
26 #include "../port/netif.h"
27
28 #include "etherif.h"
29
30 #define DEBUG           0
31 #define debug           if(DEBUG)print
32
33 enum {
34         Nrde            = 64,
35         Ntde            = 64,
36 };
37
38 #define Rbsz            ROUNDUP(sizeof(Etherpkt)+4, 4)
39
40 typedef struct Des {
41         ulong   next;
42         int     cmdsts;
43         ulong   addr;
44         Block*  bp;
45 } Des;
46
47 enum {  /* cmdsts */
48         Own     = 1<<31,        /* set by data producer to hand to consumer */
49         More    = 1<<30,        /* more of packet in next descriptor */
50         Intr    = 1<<29,        /* interrupt when device is done with it */
51         Supcrc  = 1<<28,        /* suppress crc on transmit */
52         Inccrc  = 1<<28,        /* crc included on receive (always) */
53         Ok      = 1<<27,        /* packet ok */
54         Size    = 0xFFF,        /* packet size in bytes */
55
56         /* transmit */
57         Txa     = 1<<26,        /* transmission aborted */
58         Tfu     = 1<<25,        /* transmit fifo underrun */
59         Crs     = 1<<24,        /* carrier sense lost */
60         Td      = 1<<23,        /* transmission deferred */
61         Ed      = 1<<22,        /* excessive deferral */
62         Owc     = 1<<21,        /* out of window collision */
63         Ec      = 1<<20,        /* excessive collisions */
64         /* 19-16 collision count */
65
66         /* receive */
67         Rxa     = 1<<26,        /* receive aborted (same as Rxo) */
68         Rxo     = 1<<25,        /* receive overrun */
69         Dest    = 3<<23,        /* destination class */
70           Drej= 0<<23,          /* packet was rejected */
71           Duni= 1<<23,          /* unicast */
72           Dmulti=       2<<23,          /* multicast */
73           Dbroad=       3<<23,          /* broadcast */
74         Long = 1<<22,           /* too long packet received */
75         Runt =  1<<21,          /* packet less than 64 bytes */
76         Ise =   1<<20,          /* invalid symbol */
77         Crce =  1<<19,          /* invalid crc */
78         Fae =   1<<18,          /* frame alignment error */
79         Lbp =   1<<17,          /* loopback packet */
80         Col =   1<<16,          /* collision during receive */
81 };
82
83 enum {                          /* PCI vendor & device IDs */
84         Nat83815        = (0x0020<<16)|0x100B,
85         SiS =   0x1039,
86         SiS900 =        (0x0900<<16)|SiS,
87         SiS7016 =       (0x7016<<16)|SiS,
88
89         SiS630bridge    = 0x0008,
90
91         /* SiS 900 PCI revision codes */
92         SiSrev630s =    0x81,
93         SiSrev630e =    0x82,
94         SiSrev630ea1 =  0x83,
95
96         SiSeenodeaddr = 8,              /* short addr of SiS eeprom mac addr */
97         SiS630eenodeaddr =      9,      /* likewise for the 630 */
98         Nseenodeaddr =  6,              /* " for NS eeprom */
99         Nat83815avng =  0x403,
100         Nat83816avng =  0x505,          /* 83816 acts like submodel of 83815 */
101                                         /* using reg. 0x58 to disambiguate. */
102 };
103
104 typedef struct Ctlr Ctlr;
105 typedef struct Ctlr {
106         int     port;
107         Pcidev* pcidev;
108         Ctlr*   next;
109         int     active;
110         int     id;                     /* (pcidev->did<<16)|pcidev->vid */
111
112         ushort  srom[0xB+1];
113         uchar   sromea[Eaddrlen];       /* MAC address */
114
115         uchar   fd;                     /* option or auto negotiation */
116
117         int     mbps;
118
119         Lock    lock;
120
121         Des*    rdr;                    /* receive descriptor ring */
122         int     nrdr;                   /* size of rdr */
123         int     rdrx;                   /* index into rdr */
124
125         Lock    tlock;
126         Des*    tdr;                    /* transmit descriptor ring */
127         int     ntdr;                   /* size of tdr */
128         int     tdrh;                   /* host index into tdr */
129         int     tdri;                   /* interface index into tdr */
130         int     ntq;                    /* descriptors active */
131         int     ntqmax;
132
133         ulong   rxa;                    /* receive statistics */
134         ulong   rxo;
135         ulong   rlong;
136         ulong   runt;
137         ulong   ise;
138         ulong   crce;
139         ulong   fae;
140         ulong   lbp;
141         ulong   col;
142         ulong   rxsovr;
143         ulong   rxorn;
144
145         ulong   txa;                    /* transmit statistics */
146         ulong   tfu;
147         ulong   crs;
148         ulong   td;
149         ulong   ed;
150         ulong   owc;
151         ulong   ec;
152         ulong   txurn;
153
154         ulong   dperr;                  /* system errors */
155         ulong   rmabt;
156         ulong   rtabt;
157         ulong   sserr;
158         ulong   rxsover;
159
160         ulong   version;                /* silicon version; register 0x58h */
161 } Ctlr;
162
163 static Ctlr* ctlrhead;
164 static Ctlr* ctlrtail;
165
166 enum {
167         /* registers (could memory map) */
168         Rcr=    0x00,           /* command register */
169           Rst=          1<<8,
170           Rxr=          1<<5,   /* receiver reset */
171           Txr=          1<<4,   /* transmitter reset */
172           Rxd=          1<<3,   /* receiver disable */
173           Rxe=          1<<2,   /* receiver enable */
174           Txd=          1<<1,   /* transmitter disable */
175           Txe=          1<<0,   /* transmitter enable */
176         Rcfg=   0x04,           /* configuration */
177           Lnksts=       1<<31,  /* link good */
178           Speed100=     1<<30,  /* 100 Mb/s link */
179           Fdup=         1<<29,  /* full duplex */
180           Pol=          1<<28,  /* polarity reversal (10baseT) */
181           Aneg_dn=      1<<27,  /* autonegotiation done */
182           Pint_acen=    1<<17,  /* PHY interrupt auto clear enable */
183           Pause_adv=    1<<16,  /* advertise pause during auto neg */
184           Paneg_ena=    1<<13,  /* auto negotiation enable */
185           Paneg_all=    7<<13,  /* auto negotiation enable 10/100 half & full */
186           Ext_phy=      1<<12,  /* enable MII for external PHY */
187           Phy_rst=      1<<10,  /* reset internal PHY */
188           Phy_dis=      1<<9,   /* disable internal PHY (eg, low power) */
189           Req_alg=      1<<7,   /* PCI bus request: set means less aggressive */
190           Sb=           1<<6,   /* single slot back-off not random */
191           Pow=          1<<5,   /* out of window timer selection */
192           Exd=          1<<4,   /* disable excessive deferral timer */
193           Pesel=        1<<3,   /* parity error algorithm selection */
194           Brom_dis=     1<<2,   /* disable boot rom interface */
195           Bem=          1<<0,   /* big-endian mode */
196         Rmear=  0x08,           /* eeprom access */
197           Mdc=          1<<6,   /* MII mangement check */
198           Mddir=        1<<5,   /* MII management direction */
199           Mdio=         1<<4,   /* MII mangement data */
200           Eesel=        1<<3,   /* EEPROM chip select */
201           Eeclk=        1<<2,   /* EEPROM clock */
202           Eedo=         1<<1,   /* EEPROM data out (from chip) */
203           Eedi=         1<<0,   /* EEPROM data in (to chip) */
204         Rptscr= 0x0C,           /* pci test control */
205         Risr=   0x10,           /* interrupt status */
206           Txrcmp=       1<<25,  /* transmit reset complete */
207           Rxrcmp=       1<<24,  /* receiver reset complete */
208           Dperr=        1<<23,  /* detected parity error */
209           Sserr=        1<<22,  /* signalled system error */
210           Rmabt=        1<<21,  /* received master abort */
211           Rtabt=        1<<20,  /* received target abort */
212           Rxsovr=       1<<16,  /* RX status FIFO overrun */
213           Hiberr=       1<<15,  /* high bits error set (OR of 25-16) */
214           Phy=          1<<14,  /* PHY interrupt */
215           Pme=          1<<13,  /* power management event (wake online) */
216           Swi=          1<<12,  /* software interrupt */
217           Mib=          1<<11,  /* MIB service */
218           Txurn=        1<<10,  /* TX underrun */
219           Txidle=       1<<9,   /* TX idle */
220           Txerr=        1<<8,   /* TX packet error */
221           Txdesc=       1<<7,   /* TX descriptor (with Intr bit done) */
222           Txok=         1<<6,   /* TX ok */
223           Rxorn=        1<<5,   /* RX overrun */
224           Rxidle=       1<<4,   /* RX idle */
225           Rxearly=      1<<3,   /* RX early threshold */
226           Rxerr=        1<<2,   /* RX packet error */
227           Rxdesc=       1<<1,   /* RX descriptor (with Intr bit done) */
228           Rxok=         1<<0,   /* RX ok */
229         Rimr=   0x14,           /* interrupt mask */
230         Rier=   0x18,           /* interrupt enable */
231           Ie=           1<<0,   /* interrupt enable */
232         Rtxdp=  0x20,           /* transmit descriptor pointer */
233         Rtxcfg= 0x24,           /* transmit configuration */
234           Csi=          1<<31,  /* carrier sense ignore (needed for full duplex) */
235           Hbi=          1<<30,  /* heartbeat ignore (needed for full duplex) */
236           Atp=          1<<28,  /* automatic padding of runt packets */
237           Mxdma=        7<<20,  /* maximum dma transfer field */
238           Mxdma32=      4<<20,  /* 4x32-bit words (32 bytes) */
239           Mxdma64=      5<<20,  /* 8x32-bit words (64 bytes) */
240           Flth=         0x3F<<8,/* Tx fill threshold, units of 32 bytes (must be > Mxdma) */
241           Drth=         0x3F<<0,/* Tx drain threshold (units of 32 bytes) */
242           Flth128=      4<<8,   /* fill at 128 bytes */
243           Drth512=      16<<0,  /* drain at 512 bytes */
244         Rrxdp=  0x30,           /* receive descriptor pointer */
245         Rrxcfg= 0x34,           /* receive configuration */
246           Atx=          1<<28,  /* accept transmit packets (needed for full duplex) */
247           Rdrth=        0x1F<<1,/* Rx drain threshold (units of 32 bytes) */
248           Rdrth64=      2<<1,   /* drain at 64 bytes */
249         Rccsr=  0x3C,           /* CLKRUN control/status */
250           Pmests=       1<<15,  /* PME status */
251         Rwcsr=  0x40,           /* wake on lan control/status */
252         Rpcr=   0x44,           /* pause control/status */
253         Rrfcr=  0x48,           /* receive filter/match control */
254           Rfen=         1<<31,  /* receive filter enable */
255           Aab=          1<<30,  /* accept all broadcast */
256           Aam=          1<<29,  /* accept all multicast */
257           Aau=          1<<28,  /* accept all unicast */
258           Apm=          1<<27,  /* accept on perfect match */
259           Apat=         0xF<<23,/* accept on pattern match */
260           Aarp=         1<<22,  /* accept ARP */
261           Mhen=         1<<21,  /* multicast hash enable */
262           Uhen=         1<<20,  /* unicast hash enable */
263           Ulm=          1<<19,  /* U/L bit mask */
264                                 /* bits 0-9 are rfaddr */
265         Rrfdr=  0x4C,           /* receive filter/match data */
266         Rbrar=  0x50,           /* boot rom address */
267         Rbrdr=  0x54,           /* boot rom data */
268         Rsrr=   0x58,           /* silicon revision */
269         Rmibc=  0x5C,           /* MIB control */
270                                 /* 60-78 MIB data */
271
272         /* PHY registers */
273         Rbmcr=  0x80,           /* basic mode configuration */
274           Reset=        1<<15,
275           Sel100=       1<<13,  /* select 100Mb/sec if no auto neg */
276           Anena=        1<<12,  /* auto negotiation enable */
277           Anrestart=    1<<9,   /* restart auto negotiation */
278           Selfdx=       1<<8,   /* select full duplex if no auto neg */
279         Rbmsr=  0x84,           /* basic mode status */
280           Ancomp=       1<<5,   /* autonegotiation complete */
281         Rphyidr1= 0x88,
282         Rphyidr2= 0x8C,
283         Ranar=  0x90,           /* autonegotiation advertisement */
284         Ranlpar= 0x94,          /* autonegotiation link partner ability */
285         Raner=  0x98,           /* autonegotiation expansion */
286         Rannptr= 0x9C,          /* autonegotiation next page TX */
287         Rphysts= 0xC0,          /* PHY status */
288         Rmicr=  0xC4,           /* MII control */
289           Inten=        1<<1,   /* PHY interrupt enable */
290         Rmisr=  0xC8,           /* MII status */
291         Rfcscr= 0xD0,           /* false carrier sense counter */
292         Rrecr=  0xD4,           /* receive error counter */
293         Rpcsr=  0xD8,           /* 100Mb config/status */
294         Rphycr= 0xE4,           /* PHY control */
295         Rtbscr= 0xE8,           /* 10BaseT status/control */
296 };
297
298 /*
299  * eeprom addresses
300  *      7 to 9 (16 bit words): mac address, shifted and reversed
301  */
302
303 #define csr32r(c, r)    (inl((c)->port+(r)))
304 #define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l)))
305 #define csr16r(c, r)    (ins((c)->port+(r)))
306 #define csr16w(c, r, l) (outs((c)->port+(r), (ulong)(l)))
307
308 static void
309 dumpcregs(Ctlr *ctlr)
310 {
311         int i;
312
313         for(i=0; i<=0x5C; i+=4)
314                 print("%2.2ux %8.8lux\n", i, csr32r(ctlr, i));
315 }
316
317 static void
318 promiscuous(void* arg, int on)
319 {
320         Ctlr *ctlr;
321         ulong w;
322
323         ctlr = ((Ether*)arg)->ctlr;
324         ilock(&ctlr->lock);
325         w = csr32r(ctlr, Rrfcr);
326         if(on != ((w&Aau)!=0)){
327                 csr32w(ctlr, Rrfcr, w & ~Rfen);
328                 csr32w(ctlr, Rrfcr, Rfen | (w ^ Aau));
329         }
330         iunlock(&ctlr->lock);
331 }
332
333 static void
334 attach(Ether* ether)
335 {
336         Ctlr *ctlr;
337
338         ctlr = ether->ctlr;
339         ilock(&ctlr->lock);
340         if(0)
341                 dumpcregs(ctlr);
342         csr32w(ctlr, Rcr, Rxe);
343         iunlock(&ctlr->lock);
344 }
345
346 static long
347 ifstat(Ether* ether, void* a, long n, ulong offset)
348 {
349         Ctlr *ctlr;
350         char *buf, *p;
351         int i, l, len;
352
353         ctlr = ether->ctlr;
354
355         ether->crcs = ctlr->crce;
356         ether->frames = ctlr->runt+ctlr->ise+ctlr->rlong+ctlr->fae;
357         ether->buffs = ctlr->rxorn+ctlr->tfu;
358         ether->overflows = ctlr->rxsovr;
359
360         if(n == 0)
361                 return 0;
362
363         p = malloc(READSTR);
364         l = snprint(p, READSTR, "Rxa: %lud\n", ctlr->rxa);
365         l += snprint(p+l, READSTR-l, "Rxo: %lud\n", ctlr->rxo);
366         l += snprint(p+l, READSTR-l, "Rlong: %lud\n", ctlr->rlong);
367         l += snprint(p+l, READSTR-l, "Runt: %lud\n", ctlr->runt);
368         l += snprint(p+l, READSTR-l, "Ise: %lud\n", ctlr->ise);
369         l += snprint(p+l, READSTR-l, "Fae: %lud\n", ctlr->fae);
370         l += snprint(p+l, READSTR-l, "Lbp: %lud\n", ctlr->lbp);
371         l += snprint(p+l, READSTR-l, "Tfu: %lud\n", ctlr->tfu);
372         l += snprint(p+l, READSTR-l, "Txa: %lud\n", ctlr->txa);
373         l += snprint(p+l, READSTR-l, "CRC Error: %lud\n", ctlr->crce);
374         l += snprint(p+l, READSTR-l, "Collision Seen: %lud\n", ctlr->col);
375         l += snprint(p+l, READSTR-l, "Frame Too Long: %lud\n", ctlr->rlong);
376         l += snprint(p+l, READSTR-l, "Runt Frame: %lud\n", ctlr->runt);
377         l += snprint(p+l, READSTR-l, "Rx Underflow Error: %lud\n", ctlr->rxorn);
378         l += snprint(p+l, READSTR-l, "Tx Underrun: %lud\n", ctlr->txurn);
379         l += snprint(p+l, READSTR-l, "Excessive Collisions: %lud\n", ctlr->ec);
380         l += snprint(p+l, READSTR-l, "Late Collision: %lud\n", ctlr->owc);
381         l += snprint(p+l, READSTR-l, "Loss of Carrier: %lud\n", ctlr->crs);
382         l += snprint(p+l, READSTR-l, "Parity: %lud\n", ctlr->dperr);
383         l += snprint(p+l, READSTR-l, "Aborts: %lud\n", ctlr->rmabt+ctlr->rtabt);
384         l += snprint(p+l, READSTR-l, "RX Status overrun: %lud\n", ctlr->rxsover);
385         snprint(p+l, READSTR-l, "ntqmax: %d\n", ctlr->ntqmax);
386         ctlr->ntqmax = 0;
387         buf = a;
388         len = readstr(offset, buf, n, p);
389         if(offset > l)
390                 offset -= l;
391         else
392                 offset = 0;
393         buf += len;
394         n -= len;
395
396         l = snprint(p, READSTR, "srom:");
397         for(i = 0; i < nelem(ctlr->srom); i++){
398                 if(i && ((i & 0x0F) == 0))
399                         l += snprint(p+l, READSTR-l, "\n     ");
400                 l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->srom[i]);
401         }
402
403         snprint(p+l, READSTR-l, "\n");
404         len += readstr(offset, buf, n, p);
405         free(p);
406
407         return len;
408 }
409
410 static void
411 txstart(Ether* ether)
412 {
413         Ctlr *ctlr;
414         Block *bp;
415         Des *des;
416         int started;
417
418         ctlr = ether->ctlr;
419         started = 0;
420         while(ctlr->ntq < ctlr->ntdr-1){
421                 bp = qget(ether->oq);
422                 if(bp == nil)
423                         break;
424                 des = &ctlr->tdr[ctlr->tdrh];
425                 des->bp = bp;
426                 des->addr = PADDR(bp->rp);
427                 ctlr->ntq++;
428                 coherence();
429                 des->cmdsts = Own | BLEN(bp);
430                 ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr);
431                 started = 1;
432         }
433         if(started){
434                 coherence();
435                 csr32w(ctlr, Rcr, Txe); /* prompt */
436         }
437
438         if(ctlr->ntq > ctlr->ntqmax)
439                 ctlr->ntqmax = ctlr->ntq;
440 }
441
442 static void
443 transmit(Ether* ether)
444 {
445         Ctlr *ctlr;
446
447         ctlr = ether->ctlr;
448         ilock(&ctlr->tlock);
449         txstart(ether);
450         iunlock(&ctlr->tlock);
451 }
452
453 static void
454 txrxcfg(Ctlr *ctlr, int txdrth)
455 {
456         ulong rx, tx;
457
458         rx = csr32r(ctlr, Rrxcfg);
459         tx = csr32r(ctlr, Rtxcfg);
460         if(ctlr->fd){
461                 rx |= Atx;
462                 tx |= Csi | Hbi;
463         }else{
464                 rx &= ~Atx;
465                 tx &= ~(Csi | Hbi);
466         }
467         tx &= ~(Mxdma|Drth|Flth);
468         tx |= Mxdma64 | Flth128 | txdrth;
469         csr32w(ctlr, Rtxcfg, tx);
470         rx &= ~(Mxdma|Rdrth);
471         rx |= Mxdma64 | Rdrth64;
472         csr32w(ctlr, Rrxcfg, rx);
473 }
474
475 static void
476 interrupt(Ureg*, void* arg)
477 {
478         int len, status, cmdsts, n;
479         Ctlr *ctlr;
480         Ether *ether;
481         Des *des;
482         Block *bp;
483
484         ether = arg;
485         ctlr = ether->ctlr;
486
487         while((status = csr32r(ctlr, Risr)) != 0){
488
489                 status &= ~(Pme|Mib);
490
491                 if(status & Hiberr){
492                         if(status & Rxsovr)
493                                 ctlr->rxsover++;
494                         if(status & Sserr)
495                                 ctlr->sserr++;
496                         if(status & Dperr)
497                                 ctlr->dperr++;
498                         if(status & Rmabt)
499                                 ctlr->rmabt++;
500                         if(status & Rtabt)
501                                 ctlr->rtabt++;
502                         status &= ~(Hiberr|Txrcmp|Rxrcmp|Rxsovr|Dperr|Sserr|Rmabt|Rtabt);
503                 }
504
505                 /* update link state */
506                 if(status&Phy){
507                         status &= ~Phy;
508                         csr32r(ctlr, Rcfg);
509                         n = csr32r(ctlr, Rcfg);
510 //                      iprint("83815 phy %x %x\n", n, n&Lnksts);
511                         ether->link = (n&Lnksts) != 0;
512                 }
513
514                 /*
515                  * Received packets.
516                  */
517                 if(status & (Rxdesc|Rxok|Rxerr|Rxearly|Rxorn)){
518                         des = &ctlr->rdr[ctlr->rdrx];
519                         while((cmdsts = des->cmdsts) & Own){
520                                 if((cmdsts&Ok) == 0){
521                                         if(cmdsts & Rxa)
522                                                 ctlr->rxa++;
523                                         if(cmdsts & Rxo)
524                                                 ctlr->rxo++;
525                                         if(cmdsts & Long)
526                                                 ctlr->rlong++;
527                                         if(cmdsts & Runt)
528                                                 ctlr->runt++;
529                                         if(cmdsts & Ise)
530                                                 ctlr->ise++;
531                                         if(cmdsts & Crce)
532                                                 ctlr->crce++;
533                                         if(cmdsts & Fae)
534                                                 ctlr->fae++;
535                                         if(cmdsts & Lbp)
536                                                 ctlr->lbp++;
537                                         if(cmdsts & Col)
538                                                 ctlr->col++;
539                                 }
540                                 else if(bp = iallocb(Rbsz)){
541                                         len = (cmdsts&Size)-4;
542                                         if(len <= 0){
543                                                 debug("ns83815: packet len %d <=0\n", len);
544                                                 freeb(des->bp);
545                                         }else{
546                                                 des->bp->wp = des->bp->rp+len;
547                                                 etheriq(ether, des->bp, 1);
548                                         }
549                                         des->bp = bp;
550                                         des->addr = PADDR(bp->rp);
551                                         coherence();
552                                 }else{
553                                         debug("ns83815: interrupt: iallocb for input buffer failed\n");
554                                         des->bp->next = 0;
555                                 }
556
557                                 des->cmdsts = Rbsz;
558                                 coherence();
559
560                                 ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr);
561                                 des = &ctlr->rdr[ctlr->rdrx];
562                         }
563                         status &= ~(Rxdesc|Rxok|Rxerr|Rxearly|Rxorn);
564                 }
565
566                 /*
567                  * Check the transmit side:
568                  *      check for Transmit Underflow and Adjust
569                  *      the threshold upwards;
570                  *      free any transmitted buffers and try to
571                  *      top-up the ring.
572                  */
573                 if(status & Txurn){
574                         ctlr->txurn++;
575                         ilock(&ctlr->lock);
576                         /* change threshold */
577                         iunlock(&ctlr->lock);
578                         status &= ~(Txurn);
579                 }
580
581                 ilock(&ctlr->tlock);
582                 while(ctlr->ntq){
583                         des = &ctlr->tdr[ctlr->tdri];
584                         cmdsts = des->cmdsts;
585                         if(cmdsts & Own)
586                                 break;
587
588                         if((cmdsts & Ok) == 0){
589                                 if(cmdsts & Txa)
590                                         ctlr->txa++;
591                                 if(cmdsts & Tfu)
592                                         ctlr->tfu++;
593                                 if(cmdsts & Td)
594                                         ctlr->td++;
595                                 if(cmdsts & Ed)
596                                         ctlr->ed++;
597                                 if(cmdsts & Owc)
598                                         ctlr->owc++;
599                                 if(cmdsts & Ec)
600                                         ctlr->ec++;
601                                 ether->oerrs++;
602                         }
603
604                         freeb(des->bp);
605                         des->bp = nil;
606                         des->cmdsts = 0;
607
608                         ctlr->ntq--;
609                         ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr);
610                 }
611                 txstart(ether);
612                 iunlock(&ctlr->tlock);
613
614                 status &= ~(Txurn|Txidle|Txerr|Txdesc|Txok);
615
616                 /*
617                  * Anything left not catered for?
618                  */
619                 if(status)
620                         print("#l%d: status %8.8uX\n", ether->ctlrno, status);
621         }
622 }
623
624 static void
625 ctlrinit(Ether* ether)
626 {
627         Ctlr *ctlr;
628         Des *des, *last;
629
630         ctlr = ether->ctlr;
631
632         /*
633          * Allocate suitable aligned descriptors
634          * for the transmit and receive rings;
635          * initialise the receive ring;
636          * initialise the transmit ring;
637          * unmask interrupts and start the transmit side.
638          */
639         des = xspanalloc((ctlr->nrdr+ctlr->ntdr)*sizeof(Des), 32, 0);
640         ctlr->tdr = des;
641         ctlr->rdr = des+ctlr->ntdr;
642
643         last = nil;
644         for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){
645                 des->bp = iallocb(Rbsz);
646                 if(des->bp == nil)
647                         error(Enomem);
648                 des->cmdsts = Rbsz;
649                 des->addr = PADDR(des->bp->rp);
650                 if(last != nil)
651                         last->next = PADDR(des);
652                 last = des;
653         }
654         ctlr->rdr[ctlr->nrdr-1].next = PADDR(ctlr->rdr);
655         ctlr->rdrx = 0;
656         csr32w(ctlr, Rrxdp, PADDR(ctlr->rdr));
657
658         last = nil;
659         for(des = ctlr->tdr; des < &ctlr->tdr[ctlr->ntdr]; des++){
660                 des->cmdsts = 0;
661                 des->bp = nil;
662                 des->addr = ~0;
663                 if(last != nil)
664                         last->next = PADDR(des);
665                 last = des;
666         }
667         ctlr->tdr[ctlr->ntdr-1].next = PADDR(ctlr->tdr);
668         ctlr->tdrh = 0;
669         ctlr->tdri = 0;
670         csr32w(ctlr, Rtxdp, PADDR(ctlr->tdr));
671
672         txrxcfg(ctlr, Drth512);
673
674         csr32w(ctlr, Rimr, Dperr|Sserr|Rmabt|Rtabt|Rxsovr|Hiberr|Txurn|Txerr|
675                 Txdesc|Txok|Rxorn|Rxerr|Rxdesc|Rxok);   /* Phy|Pme|Mib */
676         csr32w(ctlr, Rmicr, Inten);     /* enable phy interrupts */
677         csr32r(ctlr, Risr);             /* clear status */
678         csr32w(ctlr, Rier, Ie);
679 }
680
681 static void
682 eeclk(Ctlr *ctlr, int clk)
683 {
684         csr32w(ctlr, Rmear, Eesel | clk);
685         microdelay(2);
686 }
687
688 static void
689 eeidle(Ctlr *ctlr)
690 {
691         int i;
692
693         eeclk(ctlr, 0);
694         eeclk(ctlr, Eeclk);
695         for(i=0; i<25; i++){
696                 eeclk(ctlr, 0);
697                 eeclk(ctlr, Eeclk);
698         }
699         eeclk(ctlr, 0);
700         csr32w(ctlr, Rmear, 0);
701         microdelay(2);
702 }
703
704 static ushort
705 eegetw(Ctlr *ctlr, int a)
706 {
707         int d, i, w;
708
709         eeidle(ctlr);
710         eeclk(ctlr, 0);
711         eeclk(ctlr, Eeclk);
712         d = 0x180 | a;
713         for(i=0x400; i; i>>=1){
714                 if(d & i)
715                         csr32w(ctlr, Rmear, Eesel|Eedi);
716                 else
717                         csr32w(ctlr, Rmear, Eesel);
718                 eeclk(ctlr, Eeclk);
719                 eeclk(ctlr, 0);
720                 microdelay(2);
721         }
722         w = 0;
723         for(i=0x8000; i; i >>= 1){
724                 eeclk(ctlr, Eeclk);
725                 if(csr32r(ctlr, Rmear) & Eedo)
726                         w |= i;
727                 microdelay(2);
728                 eeclk(ctlr, 0);
729         }
730         eeidle(ctlr);
731         return w;
732 }
733
734 static int
735 resetctlr(Ctlr *ctlr)
736 {
737         int i;
738
739         /*
740          * Soft-reset the controller
741          */
742         csr32w(ctlr, Rcr, Rst);
743         for(i=0;; i++){
744                 if(i > 100){
745                         print("ns83815: soft reset did not complete\n");
746                         return -1;
747                 }
748                 microdelay(250);
749                 if((csr32r(ctlr, Rcr) & Rst) == 0)
750                         break;
751                 delay(1);
752         }
753         return 0;
754 }
755
756 static void
757 shutdown(Ether* ether)
758 {
759         Ctlr *ctlr = ether->ctlr;
760
761 print("ether83815 shutting down\n");
762         csr32w(ctlr, Rcr, Rxd|Txd);     /* disable transceiver */
763         resetctlr(ctlr);
764 }
765
766 static int
767 softreset(Ctlr* ctlr, int resetphys)
768 {
769         int i, w;
770
771         /*
772          * Soft-reset the controller
773          */
774         resetctlr(ctlr);
775         csr32w(ctlr, Rccsr, Pmests);
776         csr32w(ctlr, Rccsr, 0);
777         csr32w(ctlr, Rcfg, csr32r(ctlr, Rcfg) | Pint_acen);
778         ctlr->version = csr32r(ctlr, Rsrr);
779         if(resetphys){
780                 /*
781                  * Soft-reset the PHY
782                  */
783                 csr32w(ctlr, Rbmcr, Reset);
784                 for(i=0;; i++){
785                         if(i > 100){
786                                 print("ns83815: PHY soft reset time out\n");
787                                 return -1;
788                         }
789                         if((csr32r(ctlr, Rbmcr) & Reset) == 0)
790                                 break;
791                         delay(1);
792                 }
793         }
794
795         /*
796          * Initialisation values, in sequence (see 4.4 Recommended Registers Configuration)
797          */
798         csr16w(ctlr, 0xCC, 0x0001);     /* PGSEL */
799         csr16w(ctlr, 0xE4, 0x189C);     /* PMCCSR */
800         csr16w(ctlr, 0xFC, 0x0000);     /* TSTDAT */
801         csr16w(ctlr, 0xF4, 0x5040);     /* DSPCFG */
802         csr16w(ctlr, 0xF8, 0x008C);     /* SDCFG */
803
804         /*
805          * Auto negotiate
806          */
807         csr16r(ctlr, Rbmsr);            /* clear latched bits */
808         debug("anar: %4.4ux\n", csr16r(ctlr, Ranar));
809         csr16w(ctlr, Rbmcr, Anena);
810         if(csr16r(ctlr, Ranar) == 0 || (csr32r(ctlr, Rcfg) & Aneg_dn) == 0){
811                 csr16w(ctlr, Rbmcr, Anena|Anrestart);
812                 for(i=0;; i++){
813                         if(i > 3000){
814                                 print("ns83815: auto neg timed out\n");
815                                 return -1;
816                         }
817                         if((w = csr16r(ctlr, Rbmsr)) & Ancomp)
818                                 break;
819                         delay(1);
820                 }
821                 debug("%d ms\n", i);
822                 w &= 0xFFFF;
823                 debug("bmsr: %4.4ux\n", w);
824                 USED(w);
825         }
826         debug("anar: %4.4ux\n", csr16r(ctlr, Ranar));
827         debug("anlpar: %4.4ux\n", csr16r(ctlr, Ranlpar));
828         debug("aner: %4.4ux\n", csr16r(ctlr, Raner));
829         debug("physts: %4.4ux\n", csr16r(ctlr, Rphysts));
830         debug("tbscr: %4.4ux\n", csr16r(ctlr, Rtbscr));
831         return 0;
832 }
833
834 static int
835 media(Ether* ether)
836 {
837         Ctlr* ctlr;
838         ulong cfg;
839
840         ctlr = ether->ctlr;
841         cfg = csr32r(ctlr, Rcfg);
842         ctlr->fd = (cfg & Fdup) != 0;
843         ether->link = (cfg&Lnksts) != 0;
844         return (cfg&(Lnksts|Speed100)) == Lnksts? 10: 100;
845 }
846
847 static char* mediatable[9] = {
848         "10BASE-T",                             /* TP */
849         "10BASE-2",                             /* BNC */
850         "10BASE-5",                             /* AUI */
851         "100BASE-TX",
852         "10BASE-TFD",
853         "100BASE-TXFD",
854         "100BASE-T4",
855         "100BASE-FX",
856         "100BASE-FXFD",
857 };
858
859 static int
860 is630(ulong id, Pcidev *p)
861 {
862         if(id == SiS900)
863                 switch (p->rid) {
864                 case SiSrev630s:
865                 case SiSrev630e:
866                 case SiSrev630ea1:
867                         return 1;
868                 }
869         return 0;
870 }
871
872 enum {
873         MagicReg = 0x48,
874         MagicRegSz = 1,
875         Magicrden = 0x40,       /* read enable, apparently */
876         Paddr=          0x70,   /* address port */
877         Pdata=          0x71,   /* data port */
878 };
879
880 /* rcmos() originally from LANL's SiS 900 driver's rcmos() */
881 static int
882 sisrdcmos(Ctlr *ctlr)
883 {
884         int i;
885         unsigned reg;
886         ulong port;
887         Pcidev *p;
888
889         debug("ns83815: SiS 630 rev. %ux reading mac address from cmos\n", ctlr->pcidev->rid);
890         p = pcimatch(nil, SiS, SiS630bridge);
891         if(p == nil) {
892                 print("ns83815: no SiS 630 rev. %ux bridge for mac addr\n",
893                         ctlr->pcidev->rid);
894                 return 0;
895         }
896         port = p->mem[0].bar & ~0x01;
897         debug("ns83815: SiS 630 rev. %ux reading mac addr from cmos via bridge at port 0x%lux\n", ctlr->pcidev->rid, port);
898
899         reg = pcicfgr8(p, MagicReg);
900         pcicfgw8(p, MagicReg, reg|Magicrden);
901
902         for (i = 0; i < Eaddrlen; i++) {
903                 outb(port+Paddr, SiS630eenodeaddr + i);
904                 ctlr->sromea[i] = inb(port+Pdata);
905         }
906
907         pcicfgw8(p, MagicReg, reg & ~Magicrden);
908         return 1;
909 }
910
911 /*
912  * If this is a SiS 630E chipset with an embedded SiS 900 controller,
913  * we have to read the MAC address from the APC CMOS RAM. - sez freebsd.
914  * However, CMOS *is* NVRAM normally.  See devrtc.c:440, memory.c:88.
915  */
916 static void
917 sissrom(Ctlr *ctlr)
918 {
919         union {
920                 uchar   eaddr[Eaddrlen];
921                 ushort  alignment;
922         } ee;
923         int i, off = SiSeenodeaddr, cnt = sizeof ee.eaddr / sizeof(short);
924         ushort *shp = (ushort *)ee.eaddr;
925
926         if(!is630(ctlr->id, ctlr->pcidev) || !sisrdcmos(ctlr)) {
927                 for (i = 0; i < cnt; i++)
928                         *shp++ = eegetw(ctlr, off++);
929                 memmove(ctlr->sromea, ee.eaddr, sizeof ctlr->sromea);
930         }
931 }
932
933 ushort
934 søkrisee(Ctlr *c, int n)
935 {
936         int i;
937         uint cmd;
938         ushort r;
939
940         csr32w(c, Rmear, Eesel);
941
942         cmd = 0x180|n;
943         for(i = 10; i >= 0; i--){
944                 n = 1<<3;
945                 if(cmd&(1<<i))
946                         n |= 1;
947                 csr32w(c, Rmear, n);
948                 csr32r(c, Rmear);
949                 csr32w(c, Rmear, n|4);
950                 csr32r(c, Rmear);
951         }
952
953         csr32w(c, Rmear, 1<<3);
954         csr32r(c, Rmear);
955
956         r = 0;
957         for(i = 0; i < 16; i++){
958                 csr32w(c, Rmear, 1<<3 | 1<<2);
959                 csr32r(c, Rmear);
960                 if(csr32r(c, Rmear) & 2)
961                         r |= 1<<i;
962                 csr32w(c, Rmear, 1<<3);
963                 csr32r(c, Rmear);
964         }
965
966         csr32w(c, Rmear, 1<<3);
967         csr32w(c, Rmear, 0);
968
969         return r;
970 }
971
972 static void
973 nsnormalea(Ctlr *ctlr)
974 {
975         int i, j;
976
977         /*
978          * the MAC address is reversed, straddling word boundaries
979          */
980         j = Nseenodeaddr*16 + 15;
981         for(i = 0; i < 48; i++){
982                 ctlr->sromea[i>>3] |= ((ctlr->srom[j>>4] >> (15-(j&0xF))) & 1) << (i&7);
983                 j++;
984         }
985 }
986
987 static void
988 ns403ea(Ctlr *ctlr)
989 {
990         int i;
991         ushort s, t;
992
993         s = ctlr->srom[6];
994         for(i = 0; i < 3; i++){
995                 t = ctlr->srom[i+7];
996                 ctlr->sromea[i*2]   = t<<1 | s>>15;
997                 ctlr->sromea[i*2+1] = t>>7;
998                 s = t;
999         }
1000 }
1001
1002 static void
1003 nssrom(Ctlr* ctlr)
1004 {
1005         int i, ns403;
1006         ulong vers;
1007         ushort (*ee)(Ctlr*, int);
1008
1009         vers = ctlr->version;
1010         ns403 = vers == Nat83815avng || vers == Nat83816avng;
1011         if(ns403){
1012                 ee = søkrisee;
1013                 print("soekris %lx\n", vers);
1014         }else
1015                 ee = eegetw;
1016
1017         for(i = 0; i < nelem(ctlr->srom); i++)
1018                 ctlr->srom[i] = ee(ctlr, i);
1019
1020         if(ns403)
1021                 ns403ea(ctlr);
1022         else
1023                 nsnormalea(ctlr);
1024 }
1025
1026 static void
1027 srom(Ctlr* ctlr)
1028 {
1029         memset(ctlr->sromea, 0, sizeof(ctlr->sromea));
1030         switch (ctlr->id) {
1031         case SiS900:
1032         case SiS7016:
1033                 sissrom(ctlr);
1034                 break;
1035         case Nat83815:
1036                 nssrom(ctlr);
1037                 break;
1038         default:
1039                 print("ns83815: srom: unknown id 0x%ux\n", ctlr->id);
1040                 break;
1041         }
1042 }
1043
1044 static void
1045 scanpci83815(void)
1046 {
1047         Ctlr *ctlr;
1048         Pcidev *p;
1049         ulong id;
1050
1051         p = nil;
1052         while(p = pcimatch(p, 0, 0)){
1053                 if(p->ccrb != Pcibcnet || p->ccru != 0)
1054                         continue;
1055                 id = (p->did<<16)|p->vid;
1056                 switch(id){
1057                 default:
1058                         continue;
1059
1060                 case Nat83815:
1061                         break;
1062                 case SiS900:
1063                         break;
1064                 }
1065
1066                 /*
1067                  * bar[0] is the I/O port register address and
1068                  * bar[1] is the memory-mapped register address.
1069                  */
1070                 ctlr = malloc(sizeof(Ctlr));
1071                 ctlr->port = p->mem[0].bar & ~0x01;
1072                 ctlr->pcidev = p;
1073                 ctlr->id = id;
1074
1075                 if(ioalloc(ctlr->port, p->mem[0].size, 0, "ns83815") < 0){
1076                         print("ns83815: port 0x%uX in use\n", ctlr->port);
1077                         free(ctlr);
1078                         continue;
1079                 }
1080
1081                 if(softreset(ctlr, 0) == -1){
1082                         free(ctlr);
1083                         continue;
1084                 }
1085                 srom(ctlr);
1086
1087                 if(ctlrhead != nil)
1088                         ctlrtail->next = ctlr;
1089                 else
1090                         ctlrhead = ctlr;
1091                 ctlrtail = ctlr;
1092         }
1093 }
1094
1095 /* multicast already on, don't need to do anything */
1096 static void
1097 multicast(void*, uchar*, int)
1098 {
1099 }
1100
1101 static int
1102 reset(Ether* ether)
1103 {
1104         Ctlr *ctlr;
1105         int i, x;
1106         ulong ctladdr;
1107         uchar ea[Eaddrlen];
1108         static int scandone;
1109
1110         if(scandone == 0){
1111                 scanpci83815();
1112                 scandone = 1;
1113         }
1114
1115         /*
1116          * Any adapter matches if no ether->port is supplied,
1117          * otherwise the ports must match.
1118          */
1119         for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
1120                 if(ctlr->active)
1121                         continue;
1122                 if(ether->port == 0 || ether->port == ctlr->port){
1123                         ctlr->active = 1;
1124                         break;
1125                 }
1126         }
1127         if(ctlr == nil)
1128                 return -1;
1129
1130         ether->ctlr = ctlr;
1131         ether->port = ctlr->port;
1132         ether->irq = ctlr->pcidev->intl;
1133         ether->tbdf = ctlr->pcidev->tbdf;
1134
1135         /*
1136          * Check if the adapter's station address is to be overridden.
1137          * If not, read it from the EEPROM and set in ether->ea prior to
1138          * loading the station address in the hardware.
1139          */
1140         memset(ea, 0, Eaddrlen);
1141         if(memcmp(ea, ether->ea, Eaddrlen) == 0)
1142                 memmove(ether->ea, ctlr->sromea, Eaddrlen);
1143         for(i=0; i<Eaddrlen; i+=2){
1144                 x = ether->ea[i] | (ether->ea[i+1]<<8);
1145                 ctladdr = (ctlr->id == Nat83815? i: i<<15);
1146                 csr32w(ctlr, Rrfcr, ctladdr);
1147                 csr32w(ctlr, Rrfdr, x);
1148         }
1149         csr32w(ctlr, Rrfcr, Rfen|Apm|Aab|Aam);
1150
1151         ether->mbps = media(ether);
1152
1153         /*
1154          * Look for a medium override in case there's no autonegotiation
1155          * the autonegotiation fails.
1156          */
1157
1158         for(i = 0; i < ether->nopt; i++){
1159                 if(cistrcmp(ether->opt[i], "FD") == 0){
1160                         ctlr->fd = 1;
1161                         continue;
1162                 }
1163                 for(x = 0; x < nelem(mediatable); x++){
1164                         debug("compare <%s> <%s>\n", mediatable[x],
1165                                 ether->opt[i]);
1166                         if(cistrcmp(mediatable[x], ether->opt[i]) == 0){
1167                                 if(x != 4 && x >= 3)
1168                                         ether->mbps = 100;
1169                                 else
1170                                         ether->mbps = 10;
1171                                 switch(x){
1172                                 default:
1173                                         ctlr->fd = 0;
1174                                         break;
1175
1176                                 case 0x04:              /* 10BASE-TFD */
1177                                 case 0x05:              /* 100BASE-TXFD */
1178                                 case 0x08:              /* 100BASE-FXFD */
1179                                         ctlr->fd = 1;
1180                                         break;
1181                                 }
1182                                 break;
1183                         }
1184                 }
1185         }
1186
1187         /*
1188          * Initialise descriptor rings, ethernet address.
1189          */
1190         ctlr->nrdr = Nrde;
1191         ctlr->ntdr = Ntde;
1192         pcisetbme(ctlr->pcidev);
1193         ctlrinit(ether);
1194
1195         /*
1196          * Linkage to the generic ethernet driver.
1197          */
1198         ether->attach = attach;
1199         ether->transmit = transmit;
1200         ether->interrupt = interrupt;
1201         ether->ifstat = ifstat;
1202
1203         ether->arg = ether;
1204         ether->promiscuous = promiscuous;
1205         ether->multicast = multicast;
1206         ether->shutdown = shutdown;
1207         return 0;
1208 }
1209
1210 void
1211 ether83815link(void)
1212 {
1213         addethercard("83815",  reset);
1214 }