]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ether82598.c
pc, pc64: more conservative pcirouting
[plan9front.git] / sys / src / 9 / pc / ether82598.c
1 /*
2  * intel 10GB ethernet pci-express driver
3  * copyright © 2007, coraid, inc.
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 "etherif.h"
14
15 /*
16  * // comments note conflicts with 82563-style drivers,
17  * and the registers are all different.
18  */
19
20 enum {
21         /* general */
22         Ctrl            = 0x00000/4,    /* Device Control */
23         Status          = 0x00008/4,    /* Device Status */
24         Ctrlext         = 0x00018/4,    /* Extended Device Control */
25         Esdp            = 0x00020/4,    /* extended sdp control */
26         Esodp           = 0x00028/4,    /* extended od sdp control */
27         Ledctl          = 0x00200/4,    /* led control */
28         Tcptimer        = 0x0004c/4,    /* tcp timer */
29         Ecc             = 0x110b0/4,    /* errata ecc control magic */
30
31         /* nvm */
32         Eec             = 0x10010/4,    /* eeprom/flash control */
33         Eerd            = 0x10014/4,    /* eeprom read */
34         Fla             = 0x1001c/4,    /* flash access */
35         Flop            = 0x1013c/4,    /* flash opcode */
36         Grc             = 0x10200/4,    /* general rx control */
37
38         /* interrupt */
39         Icr             = 0x00800/4,    /* interrupt cause read */
40         Ics             = 0x00808/4,    /* " set */
41         Ims             = 0x00880/4,    /* " mask read/set */
42         Imc             = 0x00888/4,    /* " mask clear */
43         Iac             = 0x00810/4,    /* " ayto clear */
44         Iam             = 0x00890/4,    /* " auto mask enable */
45         Itr             = 0x00820/4,    /* " throttling rate (0-19) */
46         Ivar            = 0x00900/4,    /* " vector allocation regs. */
47         /* msi interrupt */
48         Msixt           = 0x0000/4,     /* msix table (bar3) */
49         Msipba          = 0x2000/4,     /* msix pending bit array (bar3) */
50         Pbacl           = 0x11068/4,    /* pba clear */
51         Gpie            = 0x00898/4,    /* general purpose int enable */
52
53         /* flow control */
54         Pfctop          = 0x03008/4,    /* priority flow ctl type opcode */
55         Fcttv           = 0x03200/4,    /* " transmit timer value (0-3) */
56         Fcrtl           = 0x03220/4,    /* " rx threshold low (0-7) +8n */
57         Fcrth           = 0x03260/4,    /* " rx threshold high (0-7) +8n */
58         Rcrtv           = 0x032a0/4,    /* " refresh value threshold */
59         Tfcs            = 0x0ce00/4,    /* " tx status */
60
61         /* rx dma */
62         Rbal            = 0x01000/4,    /* rx desc base low (0-63) +0x40n */
63         Rbah            = 0x01004/4,    /* " high */
64         Rdlen           = 0x01008/4,    /* " length */
65         Rdh             = 0x01010/4,    /* " head */
66         Rdt             = 0x01018/4,    /* " tail */
67         Rxdctl          = 0x01028/4,    /* " control */
68
69         Srrctl          = 0x02100/4,    /* split and replication rx ctl. */
70         Dcarxctl        = 0x02200/4,    /* rx dca control */
71         Rdrxctl         = 0x02f00/4,    /* rx dma control */
72         Rxpbsize        = 0x03c00/4,    /* rx packet buffer size */
73         Rxctl           = 0x03000/4,    /* rx control */
74         Dropen          = 0x03d04/4,    /* drop enable control */
75
76         /* rx */
77         Rxcsum          = 0x05000/4,    /* rx checksum control */
78         Rfctl           = 0x04008/4,    /* rx filter control */
79         Mta             = 0x05200/4,    /* multicast table array (0-127) */
80         Ral             = 0x05400/4,    /* rx address low */
81         Rah             = 0x05404/4,
82         Psrtype         = 0x05480/4,    /* packet split rx type. */
83         Vfta            = 0x0a000/4,    /* vlan filter table array. */
84         Fctrl           = 0x05080/4,    /* filter control */
85         Vlnctrl         = 0x05088/4,    /* vlan control */
86         Msctctrl        = 0x05090/4,    /* multicast control */
87         Mrqc            = 0x05818/4,    /* multiple rx queues cmd */
88         Vmdctl          = 0x0581c/4,    /* vmdq control */
89         Imir            = 0x05a80/4,    /* immediate irq rx (0-7) */
90         Imirext         = 0x05aa0/4,    /* immediate irq rx ext */
91         Imirvp          = 0x05ac0/4,    /* immediate irq vlan priority */
92         Reta            = 0x05c00/4,    /* redirection table */
93         Rssrk           = 0x05c80/4,    /* rss random key */
94
95         /* tx */
96         Tdbal           = 0x06000/4,    /* tx desc base low +0x40n */
97         Tdbah           = 0x06004/4,    /* " high */
98         Tdlen           = 0x06008/4,    /* " len */
99         Tdh             = 0x06010/4,    /* " head */
100         Tdt             = 0x06018/4,    /* " tail */
101         Txdctl          = 0x06028/4,    /* " control */
102         Tdwbal          = 0x06038/4,    /* " write-back address low */
103         Tdwbah          = 0x0603c/4,
104
105         Dtxctl          = 0x07e00/4,    /* tx dma control */
106         Tdcatxctrl      = 0x07200/4,    /* tx dca register (0-15) */
107         Tipg            = 0x0cb00/4,    /* tx inter-packet gap */
108         Txpbsize        = 0x0cc00/4,    /* tx packet-buffer size (0-15) */
109
110         /* mac */
111         Hlreg0          = 0x04240/4,    /* highlander control reg 0 */
112         Hlreg1          = 0x04244/4,    /* highlander control reg 1 (ro) */
113         Msca            = 0x0425c/4,    /* mdi signal cmd & addr */
114         Msrwd           = 0x04260/4,    /* mdi single rw data */
115         Mhadd           = 0x04268/4,    /* mac addr high & max frame */
116         Pcss1           = 0x04288/4,    /* xgxs status 1 */
117         Pcss2           = 0x0428c/4,
118         Xpcss           = 0x04290/4,    /* 10gb-x pcs status */
119         Serdesc         = 0x04298/4,    /* serdes control */
120         Macs            = 0x0429c/4,    /* fifo control & report */
121         Autoc           = 0x042a0/4,    /* autodetect control & status */
122         Links           = 0x042a4/4,    /* link status */
123         Autoc2          = 0x042a8/4,
124 };
125
126 enum {
127         /* Ctrl */
128         Rst             = 1<<26,        /* full nic reset */
129
130         /* Txdctl */
131         Ten             = 1<<25,
132
133         /* Fctrl */
134         Bam             = 1<<10,        /* broadcast accept mode */
135         Upe             = 1<<9,         /* unicast promiscuous */
136         Mpe             = 1<<8,         /* multicast promiscuous */
137
138         /* Rxdctl */
139         Pthresh         = 0,            /* prefresh threshold shift in bits */
140         Hthresh         = 8,            /* host buffer minimum threshold " */
141         Wthresh         = 16,           /* writeback threshold */
142         Renable         = 1<<25,
143
144         /* Rxctl */
145         Rxen            = 1<<0,
146         Dmbyps          = 1<<1,
147
148         /* Rdrxctl */
149         Rdmt½          = 0,
150         Rdmt¼          = 1,
151         Rdmt⅛         = 2,
152
153         /* Rxcsum */
154         Ippcse          = 1<<12,        /* ip payload checksum enable */
155
156         /* Eerd */
157         EEstart         = 1<<0,         /* Start Read */
158         EEdone          = 1<<1,         /* Read done */
159
160         /* interrupts */
161         Irx0            = 1<<0,         /* driver defined */
162         Itx0            = 1<<1,         /* driver defined */
163         Lsc             = 1<<20,        /* link status change */
164
165         /* Links */
166         Lnkup   = 1<<30,
167         Lnkspd  = 1<<29,
168
169         /* Hlreg0 */
170         Jumboen = 1<<2,
171 };
172
173 typedef struct {
174         uint    reg;
175         char    *name;
176 } Stat;
177
178 Stat stattab[] = {
179         0x4000, "crc error",
180         0x4004, "illegal byte",
181         0x4008, "short packet",
182         0x3fa0, "missed pkt0",
183         0x4034, "mac local flt",
184         0x4038, "mac rmt flt",
185         0x4040, "rx length err",
186         0x3f60, "xon tx",
187         0xcf60, "xon rx",
188         0x3f68, "xoff tx",
189         0xcf68, "xoff rx",
190         0x405c, "rx 040",
191         0x4060, "rx 07f",
192         0x4064, "rx 100",
193         0x4068, "rx 200",
194         0x406c, "rx 3ff",
195         0x4070, "rx big",
196         0x4074, "rx ok",
197         0x4078, "rx bcast",
198         0x3fc0, "rx no buf0",
199         0x40a4, "rx runt",
200         0x40a8, "rx frag",
201         0x40ac, "rx ovrsz",
202         0x40b0, "rx jab",
203         0x40d0, "rx pkt",
204
205         0x40d4, "tx pkt",
206         0x40d8, "tx 040",
207         0x40dc, "tx 07f",
208         0x40e0, "tx 100",
209         0x40e4, "tx 200",
210         0x40e8, "tx 3ff",
211         0x40ec, "tx big",
212         0x40f4, "tx bcast",
213         0x4120, "xsum err",
214 };
215
216 /* status */
217 enum {
218         Pif     = 1<<7, /* past exact filter (sic) */
219         Ipcs    = 1<<6, /* ip checksum calcuated */
220         L4cs    = 1<<5, /* layer 2 */
221         Tcpcs   = 1<<4, /* tcp checksum calcuated */
222         Vp      = 1<<3, /* 802.1q packet matched vet */
223         Ixsm    = 1<<2, /* ignore checksum */
224         Reop    = 1<<1, /* end of packet */
225         Rdd     = 1<<0, /* descriptor done */
226 };
227
228 typedef struct {
229         u32int  addr[2];
230         ushort  length;
231         ushort  cksum;
232         uchar   status;
233         uchar   errors;
234         ushort  vlan;
235 } Rd;
236
237 enum {
238         /* Td cmd */
239         Rs      = 1<<3,
240         Ic      = 1<<2,
241         Ifcs    = 1<<1,
242         Teop    = 1<<0,
243
244         /* Td status */
245         Tdd     = 1<<0,
246 };
247
248 typedef struct {
249         u32int  addr[2];
250         ushort  length;
251         uchar   cso;
252         uchar   cmd;
253         uchar   status;
254         uchar   css;
255         ushort  vlan;
256 } Td;
257
258 enum {
259         Factive         = 1<<0,
260         Fstarted        = 1<<1,
261 };
262
263 typedef struct {
264         Pcidev  *p;
265         Ether   *edev;
266         u32int  *reg;
267         u32int  *regmsi;
268         uchar   flag;
269         int     nrd;
270         int     ntd;
271         int     rbsz;
272         Lock    slock;
273         Lock    alock;
274         QLock   tlock;
275         Rendez  lrendez;
276         Rendez  trendez;
277         Rendez  rrendez;
278         uint    im;
279         uint    lim;
280         uint    rim;
281         uint    tim;
282         Lock    imlock;
283         char    *alloc;
284
285         Rd      *rdba;
286         Block   **rb;
287         uint    rdt;
288         uint    rdfree;
289
290         Td      *tdba;
291         uint    tdh;
292         uint    tdt;
293         Block   **tb;
294
295         uchar   ra[Eaddrlen];
296         uchar   mta[128];
297         ulong   stats[nelem(stattab)];
298         uint    speeds[3];
299 } Ctlr;
300
301 /* tweakable paramaters */
302 enum {
303         Rbsz    = 12*1024,
304         Nrd     = 256,
305         Ntd     = 256,
306         Nrb     = 256,
307 };
308
309 static  Ctlr    *ctlrtab[4];
310 static  int     nctlr;
311
312 static void
313 readstats(Ctlr *c)
314 {
315         int i;
316
317         lock(&c->slock);
318         for(i = 0; i < nelem(c->stats); i++)
319                 c->stats[i] += c->reg[stattab[i].reg >> 2];
320         unlock(&c->slock);
321 }
322
323 static int speedtab[] = {
324         0,
325         1000,
326         10000,
327 };
328
329 static long
330 ifstat(Ether *e, void *a, long n, ulong offset)
331 {
332         uint i, *t;
333         char *s, *p, *q;
334         Ctlr *c;
335
336         p = s = smalloc(READSTR);
337         q = p + READSTR;
338
339         c = e->ctlr;
340         readstats(c);
341         for(i = 0; i < nelem(stattab); i++)
342                 if(c->stats[i] > 0)
343                         p = seprint(p, q, "%.10s  %uld\n", stattab[i].name,                                     c->stats[i]);
344         t = c->speeds;
345         p = seprint(p, q, "speeds: 0:%d 1000:%d 10000:%d\n", t[0], t[1], t[2]);
346         seprint(p, q, "rdfree %d rdh %d rdt %d\n", c->rdfree, c->reg[Rdt],
347                 c->reg[Rdh]);
348         n = readstr(offset, a, n, s);
349         free(s);
350
351         return n;
352 }
353
354 static void
355 im(Ctlr *c, int i)
356 {
357         ilock(&c->imlock);
358         c->im |= i;
359         c->reg[Ims] = c->im;
360         iunlock(&c->imlock);
361 }
362
363 static int
364 lim(void *v)
365 {
366         return ((Ctlr*)v)->lim != 0;
367 }
368
369 static void
370 lproc(void *v)
371 {
372         int r, i;
373         Ctlr *c;
374         Ether *e;
375
376         e = v;
377         c = e->ctlr;
378         while(waserror())
379                 ;
380         for (;;) {
381                 r = c->reg[Links];
382                 e->link = (r & Lnkup) != 0;
383                 i = 0;
384                 if(e->link)
385                         i = 1 + ((r & Lnkspd) != 0);
386                 c->speeds[i]++;
387                 e->mbps = speedtab[i];
388                 c->lim = 0;
389                 im(c, Lsc);
390                 sleep(&c->lrendez, lim, c);
391                 c->lim = 0;
392         }
393 }
394
395 static long
396 ctl(Ether *, void *, long)
397 {
398         error(Ebadarg);
399         return -1;
400 }
401
402 #define Next(x, m)      (((x)+1) & (m))
403
404 static int
405 cleanup(Ctlr *c, int tdh)
406 {
407         Block *b;
408         uint m, n;
409
410         m = c->ntd - 1;
411         while(c->tdba[n = Next(tdh, m)].status & Tdd){
412                 tdh = n;
413                 b = c->tb[tdh];
414                 c->tb[tdh] = 0;
415                 freeb(b);
416                 c->tdba[tdh].status = 0;
417         }
418         return tdh;
419 }
420
421 void
422 transmit(Ether *e)
423 {
424         uint i, m, tdt, tdh;
425         Ctlr *c;
426         Block *b;
427         Td *t;
428
429         c = e->ctlr;
430         if(!canqlock(&c->tlock)){
431                 im(c, Itx0);
432                 return;
433         }
434         tdh = c->tdh = cleanup(c, c->tdh);
435         tdt = c->tdt;
436         m = c->ntd - 1;
437         for(i = 0; i < 8; i++){
438                 if(Next(tdt, m) == tdh){
439                         im(c, Itx0);
440                         break;
441                 }
442                 if(!(b = qget(e->oq)))
443                         break;
444                 t = c->tdba + tdt;
445                 t->addr[0] = PCIWADDR(b->rp);
446                 t->length = BLEN(b);
447                 t->cmd = Rs | Ifcs | Teop;
448                 c->tb[tdt] = b;
449                 tdt = Next(tdt, m);
450         }
451         if(i){
452                 c->tdt = tdt;
453                 c->reg[Tdt] = tdt;
454         }
455         qunlock(&c->tlock);
456 }
457
458 static int
459 tim(void *c)
460 {
461         return ((Ctlr*)c)->tim != 0;
462 }
463
464 static void
465 tproc(void *v)
466 {
467         Ctlr *c;
468         Ether *e;
469
470         e = v;
471         c = e->ctlr;
472         while(waserror())
473                 ;
474         for (;;) {
475                 sleep(&c->trendez, tim, c);     /* transmit kicks us */
476                 c->tim = 0;
477                 transmit(e);
478         }
479 }
480
481 static void
482 rxinit(Ctlr *c)
483 {
484         int i;
485         Block *b;
486
487         c->reg[Rxctl] &= ~Rxen;
488         for(i = 0; i < c->nrd; i++){
489                 b = c->rb[i];
490                 c->rb[i] = 0;
491                 if(b)
492                         freeb(b);
493         }
494         c->rdfree = 0;
495
496         c->reg[Fctrl] |= Bam;
497         c->reg[Rxcsum] |= Ipcs;
498         c->reg[Srrctl] = (c->rbsz + 1023)/1024;
499         c->reg[Mhadd] = c->rbsz << 16;
500         c->reg[Hlreg0] |= Jumboen;
501
502         c->reg[Rbal] = PCIWADDR(c->rdba);
503         c->reg[Rbah] = 0;
504         c->reg[Rdlen] = c->nrd*sizeof(Rd);
505         c->reg[Rdh] = 0;
506         c->reg[Rdt] = c->rdt = 0;
507
508         c->reg[Rdrxctl] = Rdmt¼;
509         c->reg[Rxdctl] = 8<<Wthresh | 8<<Pthresh | 4<<Hthresh | Renable;
510         c->reg[Rxctl] |= Rxen | Dmbyps;
511 }
512
513 static void
514 replenish(Ctlr *c, uint rdh)
515 {
516         int rdt, m, i;
517         Block *b;
518         Rd *r;
519
520         m = c->nrd - 1;
521         i = 0;
522         for(rdt = c->rdt; Next(rdt, m) != rdh; rdt = Next(rdt, m)){
523                 b = allocb(c->rbsz+BY2PG);
524                 b->rp = (uchar*)PGROUND((uintptr)b->base);
525                 b->wp = b->rp;
526                 c->rb[rdt] = b;
527                 r = c->rdba + rdt;
528                 r->addr[0] = PCIWADDR(b->rp);
529                 r->status = 0;
530                 c->rdfree++;
531                 i++;
532         }
533         if(i)
534                 c->reg[Rdt] = c->rdt = rdt;
535 }
536
537 static int
538 rim(void *v)
539 {
540         return ((Ctlr*)v)->rim != 0;
541 }
542
543 static uchar zeroea[Eaddrlen];
544
545 void
546 rproc(void *v)
547 {
548         uint m, rdh;
549         Block *b;
550         Ctlr *c;
551         Ether *e;
552         Rd *r;
553
554         e = v;
555         c = e->ctlr;
556         m = c->nrd - 1;
557         rdh = 0;
558         while(waserror())
559                 ;
560 loop:
561         replenish(c, rdh);
562         im(c, Irx0);
563         sleep(&c->rrendez, rim, c);
564 loop1:
565         c->rim = 0;
566         if(c->nrd - c->rdfree >= 16)
567                 replenish(c, rdh);
568         r = c->rdba + rdh;
569         if(!(r->status & Rdd))
570                 goto loop;              /* UGH */
571         b = c->rb[rdh];
572         c->rb[rdh] = 0;
573         b->wp += r->length;
574         if(!(r->status & Ixsm)){
575                 if(r->status & Ipcs)
576                         b->flag |= Bipck;
577                 if(r->status & Tcpcs)
578                         b->flag |= Btcpck | Budpck;
579                 b->checksum = r->cksum;
580         }
581 //      r->status = 0;
582         etheriq(e, b, 1);
583         c->rdfree--;
584         rdh = Next(rdh, m);
585         goto loop1;                     /* UGH */
586 }
587
588 static void
589 promiscuous(void *a, int on)
590 {
591         Ctlr *c;
592         Ether *e;
593
594         e = a;
595         c = e->ctlr;
596         if(on)
597                 c->reg[Fctrl] |= Upe | Mpe;
598         else
599                 c->reg[Fctrl] &= ~(Upe | Mpe);
600 }
601
602 static void
603 multicast(void *a, uchar *ea, int on)
604 {
605         int b, i;
606         Ctlr *c;
607         Ether *e;
608
609         e = a;
610         c = e->ctlr;
611
612         /*
613          * multiple ether addresses can hash to the same filter bit,
614          * so it's never safe to clear a filter bit.
615          * if we want to clear filter bits, we need to keep track of
616          * all the multicast addresses in use, clear all the filter bits,
617          * then set the ones corresponding to in-use addresses.
618          */
619         i = ea[5] >> 1;
620         b = (ea[5]&1)<<4 | ea[4]>>4;
621         b = 1 << b;
622         if(on)
623                 c->mta[i] |= b;
624 //      else
625 //              c->mta[i] &= ~b;
626         c->reg[Mta+i] = c->mta[i];
627 }
628
629 static int
630 detach(Ctlr *c)
631 {
632         int i;
633
634         c->reg[Imc] = ~0;
635         c->reg[Ctrl] |= Rst;
636         for(i = 0; i < 100; i++){
637                 delay(1);
638                 if((c->reg[Ctrl] & Rst) == 0)
639                         break;
640         }
641         if (i >= 100)
642                 return -1;
643         /* errata */
644         delay(50);
645         c->reg[Ecc] &= ~(1<<21 | 1<<18 | 1<<9 | 1<<6);
646
647         /* not cleared by reset; kill it manually. */
648         for(i = 1; i < 16; i++)
649                 c->reg[Rah] &= ~(1 << 31);
650         for(i = 0; i < 128; i++)
651                 c->reg[Mta + i] = 0;
652         for(i = 1; i < 640; i++)
653                 c->reg[Vfta + i] = 0;
654         return 0;
655 }
656
657 static void
658 shutdown(Ether *e)
659 {
660         detach(e->ctlr);
661 }
662
663 /* ≤ 20ms */
664 static ushort
665 eeread(Ctlr *c, int i)
666 {
667         c->reg[Eerd] = EEstart | i<<2;
668         while((c->reg[Eerd] & EEdone) == 0)
669                 ;
670         return c->reg[Eerd] >> 16;
671 }
672
673 static int
674 eeload(Ctlr *c)
675 {
676         ushort u, v, p, l, i, j;
677
678         if((eeread(c, 0) & 0xc0) != 0x40)
679                 return -1;
680         u = 0;
681         for(i = 0; i < 0x40; i++)
682                 u +=  eeread(c, i);
683         for(i = 3; i < 0xf; i++){
684                 p = eeread(c, i);
685                 l = eeread(c, p++);
686                 if((int)p + l + 1 > 0xffff)
687                         continue;
688                 for(j = p; j < p + l; j++)
689                         u += eeread(c, j);
690         }
691         if(u != 0xbaba)
692                 return -1;
693         if(c->reg[Status] & (1<<3))
694                 u = eeread(c, 10);
695         else
696                 u = eeread(c, 9);
697         u++;
698         for(i = 0; i < Eaddrlen;){
699                 v = eeread(c, u + i/2);
700                 c->ra[i++] = v;
701                 c->ra[i++] = v>>8;
702         }
703         c->ra[5] += (c->reg[Status] & 0xc) >> 2;
704         return 0;
705 }
706
707 static int
708 reset(Ctlr *c)
709 {
710         int i;
711         uchar *p;
712
713         if(detach(c)){
714                 print("82598: reset timeout\n");
715                 return -1;
716         }
717         if(eeload(c)){
718                 print("82598: eeprom failure\n");
719                 return -1;
720         }
721         p = c->ra;
722         c->reg[Ral] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
723         c->reg[Rah] = p[5]<<8 | p[4] | 1<<31;
724
725         readstats(c);
726         for(i = 0; i<nelem(c->stats); i++)
727                 c->stats[i] = 0;
728
729         c->reg[Ctrlext] |= 1 << 16;
730         /* make some guesses for flow control */
731         c->reg[Fcrtl] = 0x10000 | 1<<31;
732         c->reg[Fcrth] = 0x40000 | 1<<31;
733         c->reg[Rcrtv] = 0x6000;
734
735         /* configure interrupt mapping (don't ask) */
736         c->reg[Ivar+0] =     0 | 1<<7;
737         c->reg[Ivar+64/4] =  1 | 1<<7;
738 //      c->reg[Ivar+97/4] = (2 | 1<<7) << (8*(97%4));
739
740         /* interrupt throttling goes here. */
741         for(i = Itr; i < Itr + 20; i++)
742                 c->reg[i] = 128;                /* ¼µs intervals */
743         c->reg[Itr + Itx0] = 256;
744         return 0;
745 }
746
747 static void
748 txinit(Ctlr *c)
749 {
750         Block *b;
751         int i;
752
753         c->reg[Txdctl] = 16<<Wthresh | 16<<Pthresh;
754         for(i = 0; i < c->ntd; i++){
755                 b = c->tb[i];
756                 c->tb[i] = 0;
757                 if(b)
758                         freeb(b);
759         }
760         memset(c->tdba, 0, c->ntd * sizeof(Td));
761         c->reg[Tdbal] = PCIWADDR(c->tdba);
762         c->reg[Tdbah] = 0;
763         c->reg[Tdlen] = c->ntd*sizeof(Td);
764         c->reg[Tdh] = 0;
765         c->reg[Tdt] = 0;
766         c->tdh = c->ntd - 1;
767         c->tdt = 0;
768         c->reg[Txdctl] |= Ten;
769 }
770
771 static void
772 attach(Ether *e)
773 {
774         Ctlr *c;
775         int t;
776         char buf[KNAMELEN];
777
778         c = e->ctlr;
779         c->edev = e;                    /* point back to Ether* */
780         lock(&c->alock);
781         if(c->alloc){
782                 unlock(&c->alock);
783                 return;
784         }
785
786         c->nrd = Nrd;
787         c->ntd = Ntd;
788         t  = c->nrd * sizeof *c->rdba + 255;
789         t += c->ntd * sizeof *c->tdba + 255;
790         t += (c->ntd + c->nrd) * sizeof(Block*);
791         c->alloc = malloc(t);
792         unlock(&c->alock);
793         if(c->alloc == nil)
794                 error(Enomem);
795
796         c->rdba = (Rd*)ROUNDUP((uintptr)c->alloc, 256);
797         c->tdba = (Td*)ROUNDUP((uintptr)(c->rdba + c->nrd), 256);
798         c->rb = (Block**)(c->tdba + c->ntd);
799         c->tb = (Block**)(c->rb + c->nrd);
800
801         rxinit(c);
802         txinit(c);
803
804         snprint(buf, sizeof buf, "#l%dl", e->ctlrno);
805         kproc(buf, lproc, e);
806         snprint(buf, sizeof buf, "#l%dr", e->ctlrno);
807         kproc(buf, rproc, e);
808         snprint(buf, sizeof buf, "#l%dt", e->ctlrno);
809         kproc(buf, tproc, e);
810 }
811
812 static void
813 interrupt(Ureg*, void *v)
814 {
815         int icr, im;
816         Ctlr *c;
817         Ether *e;
818
819         e = v;
820         c = e->ctlr;
821         ilock(&c->imlock);
822         c->reg[Imc] = ~0;
823         im = c->im;
824         while((icr = c->reg[Icr] & c->im) != 0){
825                 if(icr & Lsc){
826                         im &= ~Lsc;
827                         c->lim = icr & Lsc;
828                         wakeup(&c->lrendez);
829                 }
830                 if(icr & Irx0){
831                         im &= ~Irx0;
832                         c->rim = icr & Irx0;
833                         wakeup(&c->rrendez);
834                 }
835                 if(icr & Itx0){
836                         im &= ~Itx0;
837                         c->tim = icr & Itx0;
838                         wakeup(&c->trendez);
839                 }
840         }
841         c->reg[Ims] = c->im = im;
842         iunlock(&c->imlock);
843 }
844
845 static void
846 scan(void)
847 {
848         ulong io, iomsi;
849         void *mem, *memmsi;
850         int pciregs, pcimsix;
851         Ctlr *c;
852         Pcidev *p;
853
854         p = 0;
855         while(p = pcimatch(p, 0x8086, 0)){
856                 switch(p->did){
857                 case 0x10c6:            /* 82598 af dual port */
858                 case 0x10c7:            /* 82598 af single port */
859                 case 0x10b6:            /* 82598 backplane */
860                 case 0x10dd:            /* 82598 at cx4 */
861                 case 0x10ec:            /* 82598 at cx4 dual port */
862                         pcimsix = 3;
863                         break;
864                 case 0x10fb:            /* 82599 */
865                         pcimsix = 4;
866                         break;
867                 default:
868                         continue;
869                 }
870                 pciregs = 0;
871                 if(nctlr == nelem(ctlrtab)){
872                         print("i82598: too many controllers\n");
873                         return;
874                 }
875                 c = malloc(sizeof *c);
876                 if(c == nil){
877                         print("i82598: can't allocate memory\n");
878                         continue;
879                 }
880                 io = p->mem[pciregs].bar & ~0xf;
881                 mem = vmap(io, p->mem[pciregs].size);
882                 if(mem == nil){
883                         print("i82598: can't map regs %#p\n", p->mem[pciregs].bar);
884                         free(c);
885                         continue;
886                 }
887                 iomsi = p->mem[pcimsix].bar & ~0xf;
888                 memmsi = vmap(iomsi, p->mem[pcimsix].size);
889                 if(memmsi == nil){
890                         print("i82598: can't map msi-x regs %#p\n", p->mem[pcimsix].bar);
891                         vunmap(mem, p->mem[pciregs].size);
892                         free(c);
893                         continue;
894                 }
895                 c->p = p;
896                 c->reg = (u32int*)mem;
897                 c->regmsi = (u32int*)memmsi;
898                 c->rbsz = Rbsz;
899                 if(reset(c)){
900                         print("i82598: can't reset\n");
901                         free(c);
902                         vunmap(mem, p->mem[pciregs].size);
903                         vunmap(memmsi, p->mem[pcimsix].size);
904                         continue;
905                 }
906                 pcisetbme(p);
907                 ctlrtab[nctlr++] = c;
908         }
909 }
910
911 static int
912 pnp(Ether *e)
913 {
914         int i;
915         Ctlr *c = nil;
916
917         if(nctlr == 0)
918                 scan();
919         for(i = 0; i < nctlr; i++){
920                 c = ctlrtab[i];
921                 if(c == nil || c->flag & Factive)
922                         continue;
923                 if(e->port == 0 || e->port == (ulong)c->reg)
924                         break;
925         }
926         if (i >= nctlr)
927                 return -1;
928         c->flag |= Factive;
929         e->ctlr = c;
930         e->port = (uintptr)c->reg;
931         e->irq = c->p->intl;
932         e->tbdf = c->p->tbdf;
933         e->mbps = 10000;
934         e->maxmtu = c->rbsz;
935         memmove(e->ea, c->ra, Eaddrlen);
936         e->arg = e;
937         e->attach = attach;
938         e->ctl = ctl;
939         e->ifstat = ifstat;
940         e->interrupt = interrupt;
941         e->multicast = multicast;
942         e->promiscuous = promiscuous;
943         e->shutdown = shutdown;
944         e->transmit = transmit;
945
946         return 0;
947 }
948
949 void
950 ether82598link(void)
951 {
952         addethercard("i82598", pnp);
953 }