]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ether79c970.c
ether82563: fix multicast for i210
[plan9front.git] / sys / src / 9 / pc / ether79c970.c
1 /*
2  * AMD79C970
3  * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
4  * To do:
5  *      finish this rewrite
6  */
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "../port/error.h"
14 #include "../port/netif.h"
15 #include "../port/etherif.h"
16
17 enum {
18         Lognrdre        = 6,
19         Nrdre           = (1<<Lognrdre),/* receive descriptor ring entries */
20         Logntdre        = 4,
21         Ntdre           = (1<<Logntdre),/* transmit descriptor ring entries */
22
23         Rbsize          = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */
24 };
25
26 enum {                                  /* DWIO I/O resource map */
27         Aprom           = 0x0000,       /* physical address */
28         Rdp             = 0x0010,       /* register data port */
29         Rap             = 0x0014,       /* register address port */
30         Sreset          = 0x0018,       /* software reset */
31         Bdp             = 0x001C,       /* bus configuration register data port */
32 };
33
34 enum {                                  /* CSR0 */
35         Init            = 0x0001,       /* begin initialisation */
36         Strt            = 0x0002,       /* enable chip */
37         Stop            = 0x0004,       /* disable chip */
38         Tdmd            = 0x0008,       /* transmit demand */
39         Txon            = 0x0010,       /* transmitter on */
40         Rxon            = 0x0020,       /* receiver on */
41         Iena            = 0x0040,       /* interrupt enable */
42         Intr            = 0x0080,       /* interrupt flag */
43         Idon            = 0x0100,       /* initialisation done */
44         Tint            = 0x0200,       /* transmit interrupt */
45         Rint            = 0x0400,       /* receive interrupt */
46         Merr            = 0x0800,       /* memory error */
47         Miss            = 0x1000,       /* missed frame */
48         Cerr            = 0x2000,       /* collision */
49         Babl            = 0x4000,       /* transmitter timeout */
50         Err             = 0x8000,       /* Babl|Cerr|Miss|Merr */
51 };
52         
53 enum {                                  /* CSR3 */
54         Bswp            = 0x0004,       /* byte swap */
55         Emba            = 0x0008,       /* enable modified back-off algorithm */
56         Dxmt2pd         = 0x0010,       /* disable transmit two part deferral */
57         Lappen          = 0x0020,       /* look-ahead packet processing enable */
58 };
59
60 enum {                                  /* CSR4 */
61         ApadXmt         = 0x0800,       /* auto pad transmit */
62 };
63
64 enum {                                  /* CSR15 */
65         Prom            = 0x8000,       /* promiscuous mode */
66 };
67
68 typedef struct Iblock Iblock;
69 struct Iblock {                 /* Initialisation Block */
70         ushort  mode;
71         uchar   rlen;                   /* upper 4 bits */
72         uchar   tlen;                   /* upper 4 bits */
73         uchar   padr[6];
74         uchar   res[2];
75         uchar   ladr[8];
76         ulong   rdra;
77         ulong   tdra;
78 };
79
80 typedef struct Dre Dre;
81 struct Dre {                    /* descriptor ring entry */
82         ulong   addr;
83         ulong   md1;                    /* status|bcnt */
84         ulong   md2;                    /* rcc|rpc|mcnt */
85         ulong   aux;
86 };
87
88
89 enum {                                  /* md1 */
90         Enp             = 0x01000000,   /* end of packet */
91         Stp             = 0x02000000,   /* start of packet */
92         RxBuff          = 0x04000000,   /* buffer error */
93         Def             = 0x04000000,   /* deferred */
94         Crc             = 0x08000000,   /* CRC error */
95         One             = 0x08000000,   /* one retry needed */
96         Oflo            = 0x10000000,   /* overflow error */
97         More            = 0x10000000,   /* more than one retry needed */
98         Fram            = 0x20000000,   /* framing error */
99         RxErr           = 0x40000000,   /* Fram|Oflo|Crc|RxBuff */
100         TxErr           = 0x40000000,   /* Uflo|Lcol|Lcar|Rtry */
101         Own             = 0x80000000,
102 };
103
104 enum {                                  /* md2 */
105         Rtry            = 0x04000000,   /* failed after repeated retries */
106         Lcar            = 0x08000000,   /* loss of carrier */
107         Lcol            = 0x10000000,   /* late collision */
108         Uflo            = 0x40000000,   /* underflow error */
109         TxBuff          = 0x80000000,   /* buffer error */
110 };
111
112 typedef struct Ctlr Ctlr;
113 struct Ctlr {
114         Lock;
115         int     port;
116         Pcidev* pcidev;
117         Ctlr*   next;
118         int     active;
119
120         int     init;                   /* initialisation in progress */
121         Iblock  iblock;
122
123         Block** rb;
124         Dre*    rdr;                    /* receive descriptor ring */
125         int     rdrx;
126
127         Block** tb;
128         Dre*    tdr;                    /* transmit descriptor ring */
129         int     tdrh;                   /* host index into tdr */
130         int     tdri;                   /* interface index into tdr */
131         int     ntq;                    /* descriptors active */
132
133         ulong   rxbuff;                 /* receive statistics */
134         ulong   crc;
135         ulong   oflo;
136         ulong   fram;
137
138         ulong   rtry;                   /* transmit statistics */
139         ulong   lcar;
140         ulong   lcol;
141         ulong   uflo;
142         ulong   txbuff;
143
144         ulong   merr;                   /* bobf is such a whiner */
145         ulong   miss;
146         ulong   babl;
147
148         int     (*ior)(Ctlr*, int);
149         void    (*iow)(Ctlr*, int, int);
150 };
151
152 static Ctlr* ctlrhead;
153 static Ctlr* ctlrtail;
154
155 /*
156  * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above.
157  * To get to 16-bit offsets, scale down with 0x10 staying the same.
158  */
159 static int
160 io16r(Ctlr *c, int r)
161 {
162         if(r >= Rdp)
163                 r = (r-Rdp)/2+Rdp;
164         return ins(c->port+r);
165 }
166
167 static void
168 io16w(Ctlr *c, int r, int v)
169 {
170         if(r >= Rdp)
171                 r = (r-Rdp)/2+Rdp;
172         outs(c->port+r, v);
173 }
174
175 static int
176 io32r(Ctlr *c, int r)
177 {
178         return inl(c->port+r);
179 }
180
181 static void
182 io32w(Ctlr *c, int r, int v)
183 {
184         outl(c->port+r, v);
185 }
186
187 static void
188 attach(Ether*)
189 {
190 }
191
192 static long
193 ifstat(Ether* ether, void* a, long n, ulong offset)
194 {
195         char *p;
196         int len;
197         Ctlr *ctlr;
198
199         ctlr = ether->ctlr;
200
201         ether->crcs = ctlr->crc;
202         ether->frames = ctlr->fram;
203         ether->buffs = ctlr->rxbuff+ctlr->txbuff;
204         ether->overflows = ctlr->oflo;
205
206         if(n == 0)
207                 return 0;
208
209         p = smalloc(READSTR);
210         len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff);
211         len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc);
212         len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo);
213         len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram);
214         len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry);
215         len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar);
216         len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol);
217         len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo);
218         len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff);
219         len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr);
220         len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss);
221         snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl);
222
223         n = readstr(offset, a, n, p);
224         free(p);
225
226         return n;
227 }
228
229 static void
230 ringinit(Ctlr* ctlr)
231 {
232         Block *bp;
233         Dre *dre;
234         int i;
235
236         /*
237          * Initialise the receive and transmit buffer rings.
238          * The ring entries must be aligned on 16-byte boundaries.
239          *
240          * This routine is protected by ctlr->init.
241          */
242         if(ctlr->rb == nil)
243                 ctlr->rb = malloc(Nrdre*sizeof(Block*));
244         if(ctlr->rdr == 0){
245                 ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0);
246                 for(i=0; i<Nrdre; i++){
247                         bp = iallocb(Rbsize);
248                         if(bp == nil)
249                                 panic("can't allocate ethernet receive ring");
250                         ctlr->rb[i] = bp;
251                         dre = &ctlr->rdr[i];
252                         dre->addr = PADDR(bp->rp);
253                         dre->md2 = 0;
254                         dre->md1 = Own|(-Rbsize & 0xFFFF);
255                         dre->aux = 0;
256                 }
257         }
258         ctlr->rdrx = 0;
259
260         if(ctlr->tb == nil)
261                 ctlr->tb = malloc(Ntdre*sizeof(Block*));
262         if(ctlr->tdr == 0)
263                 ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0);
264         memset(ctlr->tdr, 0, Ntdre*sizeof(Dre));
265         ctlr->tdrh = ctlr->tdri = 0;
266 }
267
268 static void
269 promiscuous(void* arg, int on)
270 {
271         Ether *ether;
272         int x;
273         Ctlr *ctlr;
274
275         ether = arg;
276         ctlr = ether->ctlr;
277
278         /*
279          * Put the chip into promiscuous mode. First must wait until
280          * anyone transmitting is done, then stop the chip and put
281          * it in promiscuous mode. Restarting is made harder by the chip
282          * reloading the transmit and receive descriptor pointers with their
283          * base addresses when Strt is set (unlike the older Lance chip),
284          * so the rings must be re-initialised.
285          */
286         ilock(ctlr);
287         if(ctlr->init){
288                 iunlock(ctlr);
289                 return;
290         }
291         ctlr->init = 1;
292         iunlock(ctlr);
293
294         while(ctlr->ntq)
295                 ;
296
297         ctlr->iow(ctlr, Rdp, Stop);
298
299         ctlr->iow(ctlr, Rap, 15);
300         x = ctlr->ior(ctlr, Rdp) & ~Prom;
301         if(on || ether->nmaddr > 0)
302                 x |= Prom;
303         ctlr->iow(ctlr, Rdp, x);
304         ctlr->iow(ctlr, Rap, 0);
305
306         ringinit(ctlr);
307
308         ilock(ctlr);
309         ctlr->init = 0;
310         ctlr->iow(ctlr, Rdp, Iena|Strt);
311         iunlock(ctlr);
312 }
313
314 static void
315 multicast(void* arg, uchar*, int)
316 {
317         Ether *ether = arg;
318         promiscuous(arg, ether->prom);
319 }
320
321 static void
322 txstart(Ether* ether)
323 {
324         Ctlr *ctlr;
325         Block *bp;
326         Dre *dre;
327         int i;
328
329         ctlr = ether->ctlr;
330
331         if(ctlr->init)
332                 return;
333
334         while(ctlr->ntq < (Ntdre-1)){
335                 bp = qget(ether->oq);
336                 if(bp == nil)
337                         break;
338
339                 /*
340                  * Give ownership of the descriptor to the chip,
341                  * increment the software ring descriptor pointer
342                  * and tell the chip to poll.
343                  * There's no need to pad to ETHERMINTU
344                  * here as ApadXmt is set in CSR4.
345                  */
346                 i = ctlr->tdrh;
347                 if(ctlr->tb[i] != nil)
348                         break;
349                 dre = &ctlr->tdr[i];
350                 ctlr->tb[i] = bp;
351                 dre->addr = PADDR(bp->rp);
352                 dre->md2 = 0;
353                 dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
354                 ctlr->ntq++;
355                 ctlr->iow(ctlr, Rdp, Iena|Tdmd);
356                 ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
357         }
358 }
359
360 static void
361 transmit(Ether* ether)
362 {
363         Ctlr *ctlr;
364
365         ctlr = ether->ctlr;
366         ilock(ctlr);
367         txstart(ether);
368         iunlock(ctlr);
369 }
370
371 static void
372 interrupt(Ureg*, void* arg)
373 {
374         Ctlr *ctlr;
375         Ether *ether;
376         int csr0, len, i;
377         Dre *dre;
378         Block *bp, *bb;
379
380         ether = arg;
381         ctlr = ether->ctlr;
382
383         /*
384          * Acknowledge all interrupts and whine about those that shouldn't
385          * happen.
386          */
387 intrloop:
388         csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF;
389         ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
390         if(csr0 & Merr)
391                 ctlr->merr++;
392         if(csr0 & Miss)
393                 ctlr->miss++;
394         if(csr0 & Babl)
395                 ctlr->babl++;
396         //if(csr0 & (Babl|Miss|Merr))
397         //      print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
398         if(!(csr0 & (Rint|Tint)))
399                 return;
400
401         /*
402          * Receiver interrupt: run round the descriptor ring logging
403          * errors and passing valid receive data up to the higher levels
404          * until a descriptor is encountered still owned by the chip.
405          */
406         if(csr0 & Rint){
407                 ilock(ctlr);
408                 i = ctlr->rdrx;
409                 dre = &ctlr->rdr[i];
410                 while(!(dre->md1 & Own)){
411                         if(dre->md1 & RxErr){
412                                 if(dre->md1 & RxBuff)
413                                         ctlr->rxbuff++;
414                                 if(dre->md1 & Crc)
415                                         ctlr->crc++;
416                                 if(dre->md1 & Oflo)
417                                         ctlr->oflo++;
418                                 if(dre->md1 & Fram)
419                                         ctlr->fram++;
420                         }
421                         else if(bp = iallocb(Rbsize)){
422                                 bb = ctlr->rb[i];
423                                 ctlr->rb[i] = bp;
424                                 if(bb != nil){
425                                         len = (dre->md2 & 0x0FFF)-4;
426                                         bb->wp = bb->rp+len;
427                                         etheriq(ether, bb);
428                                 }
429                                 dre->addr = PADDR(bp->rp);
430                         }
431
432                         /*
433                          * Finished with this descriptor, reinitialise it,
434                          * give it back to the chip, then on to the next...
435                          */
436                         dre->md2 = 0;
437                         dre->md1 = Own|(-Rbsize & 0xFFFF);
438
439                         i = ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
440                         dre = &ctlr->rdr[i];
441                 }
442                 iunlock(ctlr);
443         }
444
445         /*
446          * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
447          */
448         if(csr0 & Tint){
449                 ilock(ctlr);
450                 while(ctlr->ntq){
451                         i = ctlr->tdri;
452                         dre = &ctlr->tdr[i];
453                         if(dre->md1 & Own)
454                                 break;
455         
456                         if(dre->md1 & TxErr){
457                                 if(dre->md2 & Rtry)
458                                         ctlr->rtry++;
459                                 if(dre->md2 & Lcar)
460                                         ctlr->lcar++;
461                                 if(dre->md2 & Lcol)
462                                         ctlr->lcol++;
463                                 if(dre->md2 & Uflo)
464                                         ctlr->uflo++;
465                                 if(dre->md2 & TxBuff)
466                                         ctlr->txbuff++;
467                                 ether->oerrs++;
468                         }
469                         bp = ctlr->tb[i];
470                         if(bp != nil){
471                                 ctlr->tb[i] = nil;
472                                 freeb(bp);
473                         }
474         
475                         ctlr->ntq--;
476                         ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
477                 }
478                 txstart(ether);
479                 iunlock(ctlr);
480         }
481         goto intrloop;
482 }
483
484 static void
485 amd79c970pci(void)
486 {
487         int port;
488         Ctlr *ctlr;
489         Pcidev *p;
490
491         p = nil;
492         while(p = pcimatch(p, 0x1022, 0x2000)){
493                 port = p->mem[0].bar & ~0x01;
494                 if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){
495                         print("amd79c970: port 0x%uX in use\n", port);
496                         continue;
497                 }
498                 ctlr = malloc(sizeof(Ctlr));
499                 if(ctlr == nil){
500                         print("amd79c970: can't allocate memory\n");
501                         iofree(port);
502                         continue;
503                 }
504                 ctlr->port = p->mem[0].bar & ~0x01;
505                 ctlr->pcidev = p;
506
507                 if(ctlrhead != nil)
508                         ctlrtail->next = ctlr;
509                 else
510                         ctlrhead = ctlr;
511                 ctlrtail = ctlr;
512         }
513 }
514
515 static int
516 reset(Ether* ether)
517 {
518         int x;
519         uchar ea[Eaddrlen];
520         Ctlr *ctlr;
521
522         if(ctlrhead == nil)
523                 amd79c970pci();
524
525         /*
526          * Any adapter matches if no port is supplied,
527          * otherwise the ports must match.
528          */
529         for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
530                 if(ctlr->active)
531                         continue;
532                 if(ether->port == 0 || ether->port == ctlr->port){
533                         ctlr->active = 1;
534                         break;
535                 }
536         }
537         if(ctlr == nil)
538                 return -1;
539
540         /*
541          * Allocate a controller structure and start to initialise it.
542          */
543         ether->ctlr = ctlr;
544         ether->port = ctlr->port;
545         ether->irq = ctlr->pcidev->intl;
546         ether->tbdf = ctlr->pcidev->tbdf;
547         ilock(ctlr);
548         ctlr->init = 1;
549         pcienable(ctlr->pcidev);
550         pcisetbme(ctlr->pcidev);
551
552         io32r(ctlr, Sreset);
553         io16r(ctlr, Sreset);
554
555         if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){
556                 ctlr->ior = io16r;
557                 ctlr->iow = io16w;
558         }else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){
559                 ctlr->ior = io32r;
560                 ctlr->iow = io32w;
561         }else{
562                 print("#l%d: card doesn't talk right\n", ether->ctlrno);
563                 iunlock(ctlr);
564                 return -1;
565         }
566
567         ctlr->iow(ctlr, Rap, 88);
568         x = ctlr->ior(ctlr, Rdp);
569         ctlr->iow(ctlr, Rap, 89);
570         x |= ctlr->ior(ctlr, Rdp)<<16;
571
572         switch(x&0xFFFFFFF){
573         case 0x2420003: /* PCnet/PCI 79C970 */
574         case 0x2621003: /* PCnet/PCI II 79C970A */
575                 ether->mbps = 10;
576                 break;
577         case 0x2625003: /* PCnet-FAST III 79C973 */
578                 ether->mbps = 100;
579                 break;
580         default:
581                 print("#l%d: unknown PCnet card version 0x%.7ux\n",
582                         ether->ctlrno, x&0xFFFFFFF);
583                 iunlock(ctlr);
584                 return -1;
585         }
586
587         /*
588          * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
589          * Set the auto pad transmit in CSR4.
590          */
591         ctlr->iow(ctlr, Rap, 20);
592         ctlr->iow(ctlr, Bdp, 0x0002);
593
594         ctlr->iow(ctlr, Rap, 4);
595         x = ctlr->ior(ctlr, Rdp) & 0xFFFF;
596         ctlr->iow(ctlr, Rdp, ApadXmt|x);
597
598         ctlr->iow(ctlr, Rap, 0);
599
600         /*
601          * Check if the adapter's station address is to be overridden.
602          * If not, read it from the I/O-space and set in ether->ea prior to
603          * loading the station address in the initialisation block.
604          */
605         memset(ea, 0, Eaddrlen);
606         if(!memcmp(ea, ether->ea, Eaddrlen)){
607                 x = ctlr->ior(ctlr, Aprom);
608                 ether->ea[0] = x;
609                 ether->ea[1] = x>>8;
610                 if(ctlr->ior == io16r)
611                         x = ctlr->ior(ctlr, Aprom+2);
612                 else
613                         x >>= 16;
614                 ether->ea[2] = x;
615                 ether->ea[3] = x>>8;
616                 x = ctlr->ior(ctlr, Aprom+4);
617                 ether->ea[4] = x;
618                 ether->ea[5] = x>>8;
619         }
620
621         /* VMware */
622         x = ether->ea[0]<<16 | ether->ea[1]<<8 | ether->ea[2];
623         switch(x){
624         case 0x0569:
625         case 0x0C29:
626         case 0x5056:
627                 ether->mbps = 1000;
628         }
629
630         /*
631          * Start to fill in the initialisation block
632          * (must be DWORD aligned).
633          */
634         ctlr->iblock.rlen = Lognrdre<<4;
635         ctlr->iblock.tlen = Logntdre<<4;
636         memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));
637
638         ringinit(ctlr);
639         ctlr->iblock.rdra = PADDR(ctlr->rdr);
640         ctlr->iblock.tdra = PADDR(ctlr->tdr);
641
642         /*
643          * Point the chip at the initialisation block and tell it to go.
644          * Mask the Idon interrupt and poll for completion. Strt and interrupt
645          * enables will be set later when attaching to the network.
646          */
647         x = PADDR(&ctlr->iblock);
648         ctlr->iow(ctlr, Rap, 1);
649         ctlr->iow(ctlr, Rdp, x & 0xFFFF);
650         ctlr->iow(ctlr, Rap, 2);
651         ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF);
652         ctlr->iow(ctlr, Rap, 3);
653         ctlr->iow(ctlr, Rdp, Idon);
654         ctlr->iow(ctlr, Rap, 0);
655         ctlr->iow(ctlr, Rdp, Init);
656
657         while(!(ctlr->ior(ctlr, Rdp) & Idon))
658                 ;
659
660         /*
661          * We used to set CSR0 to Idon|Stop here, and then
662          * in attach change it to Iena|Strt.  Apparently the simulated
663          * 79C970 in VMware never enables after a write of Idon|Stop,
664          * so we enable the device here now.
665          */
666         ctlr->iow(ctlr, Rdp, Iena|Strt);
667         ctlr->init = 0;
668         iunlock(ctlr);
669
670         /*
671          * Linkage to the generic ethernet driver.
672          */
673         ether->attach = attach;
674         ether->transmit = transmit;
675         ether->ifstat = ifstat;
676
677         ether->arg = ether;
678         ether->promiscuous = promiscuous;
679         ether->multicast = multicast;
680 //      ether->shutdown = shutdown;
681
682         intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
683
684         return 0;
685 }
686
687 void
688 ether79c970link(void)
689 {
690         addethercard("AMD79C970",  reset);
691 }