]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherx550.c
bda9a2662a4245be74e33327bf808adca0c6f3b9
[plan9front.git] / sys / src / 9 / pc / etherx550.c
1 /*
2  * intel 10GB ethernet pci-express driver
3  * 6.0.0:       net  02.00.00 8086/15c8  11 0:dfc0000c 2097152 4:dfe0400c 16384
4  *      Intel Corporation Ethernet Connection X553/X550-AT 10GBASE-T
5  */
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "../port/error.h"
13 #include "../port/netif.h"
14 #include "../port/etherif.h"
15
16
17 enum {
18         /* general */
19         Ctrl            = 0x00000/4,    /* Device Control */
20         Status          = 0x00008/4,    /* Device Status */
21         Ctrlext         = 0x00018/4,    /* Extended Device Control */
22         Tcptimer        = 0x0004c/4,    /* tcp timer */
23
24         /* nvm */
25         Eec             = 0x10010/4,    /* eeprom/flash control */
26         Eemngctl        = 0x10110/4,    /* Manageability EEPROM-Mode Control */
27
28         /* interrupt */
29         Icr             = 0x00800/4,    /* interrupt cause read */
30         Ics             = 0x00808/4,    /* " set */
31         Ims             = 0x00880/4,    /* " mask read/set */
32         Imc             = 0x00888/4,    /* " mask clear */
33         Iac             = 0x00810/4,    /* " auto clear */
34         Iam             = 0x00890/4,    /* " auto mask enable */
35         Itr             = 0x00820/4,    /* " throttling rate (0-19) */
36         Ivar            = 0x00900/4,    /* " vector allocation regs. */
37
38         /* rx dma */
39         Rdbal           = 0x01000/4,    /* rx desc base low (0-63) +0x40n */
40         Rdbah           = 0x01004/4,    /* " high */
41         Rdlen           = 0x01008/4,    /* " length */
42         Rdh             = 0x01010/4,    /* " head */
43         Rdt             = 0x01018/4,    /* " tail */
44         Rxdctl          = 0x01028/4,    /* " control */
45
46         Srrctl          = 0x02100/4,    /* split and replication rx ctl. */
47         Rdrxctl         = 0x02f00/4,    /* rx dma control */
48         Rxpbsize        = 0x03c00/4,    /* rx packet buffer size */
49         Rxctrl          = 0x03000/4,    /* rx control */
50
51         /* rx */
52         Rxcsum          = 0x05000/4,    /* rx checksum control */
53         Mcstctrl        = 0x05090/4,    /* multicast control register */
54         Mta             = 0x05200/4,    /* multicast table array (0-127) */
55         Ral             = 0x05400/4,    /* rx address low */
56         Rah             = 0x05404/4,
57         Vfta            = 0x0a000/4,    /* vlan filter table array. */
58         Fctrl           = 0x05080/4,    /* filter control */
59
60         /* tx */
61         Tdbal           = 0x06000/4,    /* tx desc base low +0x40n */
62         Tdbah           = 0x06004/4,    /* " high */
63         Tdlen           = 0x06008/4,    /* " len */
64         Tdh             = 0x06010/4,    /* " head */
65         Tdt             = 0x06018/4,    /* " tail */
66         Txdctl          = 0x06028/4,    /* " control */
67         Dmatxctl        = 0x04a80/4,
68
69         /* mac */
70         Hlreg0          = 0x04240/4,    /* highlander control reg 0 */
71         Hlreg1          = 0x04244/4,    /* highlander control reg 1 (ro) */
72         Maxfrs          = 0x04268/4,    /* max frame size */
73         Links           = 0x042a4/4,    /* link status */
74 };
75
76 enum {
77         /* Ctrl */
78         Rst             = 1<<26,        /* full nic reset */
79         
80         /* Ctrlext */
81         Drvload         = 1<<28,        /* Driver Load */
82         
83         /* Eec */
84         AutoRd          = 1<<9,         /* NVM auto read done */
85
86         /* Eemngctl */
87         CfgDone0        = 1<<18,        /* Configuration Done Port 0 */
88         CfgDone1        = 1<<19,        /* Configuration Done Port 1 */
89
90         /* Txdctl */
91         Pthresh         = 0,            /* prefresh threshold shift in bits */
92         Hthresh         = 8,            /* host buffer minimum threshold */
93         Wthresh         = 16,           /* writeback threshold */
94         Ten             = 1<<25,
95
96         /* Fctrl */
97         Bam             = 1<<10,        /* broadcast accept mode */
98         Upe             = 1<<9,         /* unicast promiscuous */
99         Mpe             = 1<<8,         /* multicast promiscuous */
100
101         /* Rxdctl */
102         Renable         = 1<<25,
103
104         /* Dmatxctl */
105         Txen            = 1<<0,
106
107         /* Rxctl */
108         Rxen            = 1<<0,
109
110         /* Rdrxctl */
111         Dmaidone        = 1<<3,
112
113         /* Rxcsum */
114         Ippcse          = 1<<12,        /* ip payload checksum enable */
115
116         /* Mcstctrl */
117         Mo              = 0,            /* multicast offset 47:36 */
118         Mfe             = 1<<2,         /* multicast filter enable */
119
120         /* Rah */
121         Av              = 1<<31,
122
123         /* interrupts */
124         Irx0            = 1<<0,         /* driver defined - rx interrupt */
125         Itx0            = 1<<1,         /* driver defined - tx interrupt */
126         Lsc             = 1<<20,        /* link status change */
127         
128         /* Ivar Interrupt Vector Allocation Register */
129         Intalloc0       = 0,            /* Map the 0th queue Rx interrupt to the 0th bit of EICR register */
130         Intallocval0    = 1<<7,
131         intalloc1       = 1<<8,         /* Map the 0th queue Tx interrupt to the 1st bit of EICR register */
132         Intallocval1    = 1<<15,
133
134         /* Links */
135         Lnkup   = 1<<30,
136         Lnkspd  = 1<<29,
137
138         /* Hlreg0 */
139         Jumboen = 1<<2,
140 };
141
142 typedef struct {
143         uint    reg;
144         char    *name;
145 } Stat;
146
147 static
148 Stat stattab[] = {
149         0x4000, "crc error",
150         0x4004, "illegal byte",
151         0x4008, "short packet",
152         0x3fa0, "missed pkt0",
153         0x4034, "mac local flt",
154         0x4038, "mac rmt flt",
155         0x4040, "rx length err",
156         0x405c, "rx 040",
157         0x4060, "rx 07f",
158         0x4064, "rx 100",
159         0x4068, "rx 200",
160         0x406c, "rx 3ff",
161         0x4070, "rx big",
162         0x4074, "rx ok",
163         0x4078, "rx bcast",
164         0x407c, "rx mcast",
165         0x4080, "tx ok",
166         0x40a4, "rx runt",
167         0x40a8, "rx frag",
168         0x40ac, "rx ovrsz",
169         0x40b0, "rx jab",
170         0x40d0, "rx pkt",
171         0x40d4, "tx pkt",
172         0x40d8, "tx 040",
173         0x40dc, "tx 07f",
174         0x40e0, "tx 100",
175         0x40e4, "tx 200",
176         0x40e8, "tx 3ff",
177         0x40ec, "tx big",
178         0x40f0, "tx mcast",
179         0x40f4, "tx bcast",
180         0x4120, "xsum err",
181 };
182
183 /* status */
184 enum {
185         Pif     = 1<<7, /* past exact filter (sic) */
186         Ipcs    = 1<<6, /* ip checksum calcuated */
187         L4cs    = 1<<5, /* layer 2 */
188         Udpcs   = 1<<4, /* udp checksum calcuated */
189         Vp      = 1<<3, /* 802.1q packet matched vet */
190         Reop    = 1<<1, /* end of packet */
191         Rdd     = 1<<0, /* descriptor done */
192 };
193
194 typedef struct {
195         u32int  addr[2];
196         ushort  length;
197         ushort  cksum;
198         uchar   status;
199         uchar   errors;
200         ushort  vlan;
201 } Rd;
202
203 enum {
204         /* Td cmd */
205         Rs      = 1<<3,
206         Ic      = 1<<2,
207         Ifcs    = 1<<1,
208         Teop    = 1<<0,
209
210         /* Td status */
211         Tdd     = 1<<0,
212 };
213
214 typedef struct {
215         u32int  addr[2];
216         u16int  length;
217         uchar   cso;
218         uchar   cmd;
219         uchar   status;
220         uchar   css;
221         ushort  vlan;
222 } Td;
223
224 enum {
225         Factive         = 1<<0,
226         Fstarted        = 1<<1,
227 };
228
229 typedef struct {
230         Pcidev  *p;
231         Ether   *edev;
232         uintptr io;
233         u32int  *reg;
234         u32int  *regmsi;
235         uchar   flag;
236         int     nrd;
237         int     ntd;
238         int     rbsz;
239         Lock    slock;
240         Lock    alock;
241         QLock   tlock;
242         Rendez  lrendez;
243         Rendez  trendez;
244         Rendez  rrendez;
245         uint    im;
246         uint    lim;
247         uint    rim;
248         uint    tim;
249         Lock    imlock;
250         char    *alloc;
251
252         Rd      *rdba;
253         Block   **rb;
254         uint    rdt;
255         uint    rdfree;
256
257         Td      *tdba;
258         uint    tdh;
259         uint    tdt;
260         Block   **tb;
261
262         uchar   ra[Eaddrlen];
263         u32int  mta[128];
264         ulong   stats[nelem(stattab)];
265         uint    speeds[3];
266 } Ctlr;
267
268 /* tweakable paramaters */
269 enum {
270         Mtu     = 12*1024,
271         Nrd     = 256,
272         Ntd     = 256,
273         Nrb     = 256,
274 };
275
276 static  Ctlr    *ctlrtab[4];
277 static  int     nctlr;
278
279 static void
280 readstats(Ctlr *c)
281 {
282         int i;
283
284         lock(&c->slock);
285         for(i = 0; i < nelem(c->stats); i++)
286                 c->stats[i] += c->reg[stattab[i].reg >> 2];
287         unlock(&c->slock);
288 }
289
290 static int speedtab[] = {
291         0,
292         1000,
293         10000,
294 };
295
296 static long
297 ifstat(Ether *e, void *a, long n, ulong offset)
298 {
299         uint i, *t;
300         char *s, *p, *q;
301         Ctlr *c;
302
303         p = s = smalloc(READSTR);
304         q = p + READSTR;
305
306         c = e->ctlr;
307         readstats(c);
308         for(i = 0; i < nelem(stattab); i++)
309                 if(c->stats[i] > 0)
310                         p = seprint(p, q, "%.10s  %uld\n", stattab[i].name,
311                                         c->stats[i]);
312         t = c->speeds;
313         p = seprint(p, q, "speeds: 0:%d 1000:%d 10000:%d\n", t[0], t[1], t[2]);
314         seprint(p, q, "rdfree %d rdh %d rdt %d\n", c->rdfree, c->reg[Rdt],
315                 c->reg[Rdh]);
316         n = readstr(offset, a, n, s);
317         free(s);
318
319         return n;
320 }
321
322 static void
323 im(Ctlr *c, int i)
324 {
325         ilock(&c->imlock);
326         c->im |= i;
327         c->reg[Ims] = c->im;
328         iunlock(&c->imlock);
329 }
330
331 static int
332 lim(void *v)
333 {
334         return ((Ctlr*)v)->lim != 0;
335 }
336
337 static void
338 lproc(void *v)
339 {
340         int r, i;
341         Ctlr *c;
342         Ether *e;
343
344         e = v;
345         c = e->ctlr;
346         while(waserror())
347                 ;
348         for (;;) {
349                 r = c->reg[Links];
350                 e->link = (r & Lnkup) != 0;
351                 i = 0;
352                 if(e->link)
353                         i = 1 + ((r & Lnkspd) != 0);
354                 c->speeds[i]++;
355                 e->mbps = speedtab[i];
356                 c->lim = 0;
357                 im(c, Lsc);
358                 sleep(&c->lrendez, lim, c);
359                 c->lim = 0;
360         }
361 }
362
363 static long
364 ctl(Ether *, void *, long)
365 {
366         error(Ebadarg);
367         return -1;
368 }
369
370 #define Next(x, m)      (((x)+1) & (m))
371
372 static int
373 cleanup(Ctlr *c, int tdh)
374 {
375         Block *b;
376         uint m, n;
377
378         m = c->ntd - 1;
379         while(c->tdba[n = Next(tdh, m)].status & Tdd){
380                 tdh = n;
381                 b = c->tb[tdh];
382                 c->tb[tdh] = 0;
383                 freeb(b);
384                 c->tdba[tdh].status = 0;
385         }
386         return tdh;
387 }
388
389 static void
390 transmit(Ether *e)
391 {
392         uint i, m, tdt, tdh;
393         Ctlr *c;
394         Block *b;
395         Td *t;
396
397         c = e->ctlr;
398         if(!canqlock(&c->tlock)){
399                 im(c, Itx0);
400                 return;
401         }
402         tdh = c->tdh = cleanup(c, c->tdh);
403         tdt = c->tdt;
404         m = c->ntd - 1;
405         for(i = 0; i < 8; i++){
406                 if(Next(tdt, m) == tdh){
407                         im(c, Itx0);
408                         break;
409                 }
410                 if(!(b = qget(e->oq)))
411                         break;
412                 t = c->tdba + tdt;
413                 t->addr[0] = PCIWADDR(b->rp);
414                 t->length = BLEN(b);
415                 t->cmd = Rs | Ifcs | Teop;
416                 c->tb[tdt] = b;
417                 tdt = Next(tdt, m);
418         }
419         if(i){
420                 c->tdt = tdt;
421                 c->reg[Tdt] = tdt;
422         }
423         qunlock(&c->tlock);
424 }
425
426 static int
427 tim(void *c)
428 {
429         return ((Ctlr*)c)->tim != 0;
430 }
431
432 static void
433 tproc(void *v)
434 {
435         Ctlr *c;
436         Ether *e;
437
438         e = v;
439         c = e->ctlr;
440         while(waserror())
441                 ;
442         for (;;) {
443                 sleep(&c->trendez, tim, c);     /* transmit kicks us */
444                 c->tim = 0;
445                 transmit(e);
446         }
447 }
448
449 static void
450 rxinit(Ctlr *c)
451 {
452         int i;
453         Block *b;
454
455         c->reg[Rxctrl] &= ~Rxen;
456         /* Pg 144 Step 2
457                 Receive buffers of appropriate size should be allocated
458                 and pointers to these buffers should be stored in the
459                 descriptor ring - replinish() does this? */
460         for(i = 0; i < c->nrd; i++){
461                 b = c->rb[i];
462                 c->rb[i] = 0;
463                 if(b)
464                         freeb(b);
465         }
466         c->rdfree = 0;
467
468         c->reg[Fctrl] |= Bam;
469         c->reg[Rxcsum] |= Ippcse;
470         c->reg[Srrctl] = c->rbsz / 1024;
471         c->reg[Maxfrs] = c->rbsz << 16;
472         c->reg[Hlreg0] |= Jumboen;
473
474         c->reg[Rdbal] = PCIWADDR(c->rdba);
475         c->reg[Rdbah] = 0;
476         c->reg[Rdlen] = c->nrd*sizeof(Rd);
477         c->reg[Rdh] = 0;
478         c->reg[Rdt] = c->rdt = 0;
479
480         c->reg[Rxdctl] = Renable;
481         while((c->reg[Rxdctl] & Renable) == 0)
482                 ;
483         /* TODO? bump the tail pointer RDT to enable descriptors
484                 fetching by setting it to the ring length minus 1. Pg 145 */
485         c->reg[Rxctrl] |= Rxen;
486 }
487
488 static void
489 replenish(Ctlr *c, uint rdh)
490 {
491         int rdt, m, i;
492         Block *b;
493         Rd *r;
494
495         m = c->nrd - 1;
496         i = 0;
497         for(rdt = c->rdt; Next(rdt, m) != rdh; rdt = Next(rdt, m)){
498                 b = allocb(c->rbsz+BY2PG);
499                 b->rp = (uchar*)PGROUND((uintptr)b->base);
500                 b->wp = b->rp;
501                 c->rb[rdt] = b;
502                 r = c->rdba + rdt;
503                 r->addr[0] = PCIWADDR(b->rp);
504                 r->status = 0;
505                 c->rdfree++;
506                 i++;
507         }
508         if(i)
509                 c->reg[Rdt] = c->rdt = rdt;
510 }
511
512 static int
513 rim(void *v)
514 {
515         return ((Ctlr*)v)->rim != 0;
516 }
517
518 static uchar zeroea[Eaddrlen];
519
520 static void
521 rproc(void *v)
522 {
523         uint m, rdh;
524         Block *b;
525         Ctlr *c;
526         Ether *e;
527         Rd *r;
528
529         e = v;
530         c = e->ctlr;
531         m = c->nrd - 1;
532         rdh = 0;
533         while(waserror())
534                 ;
535 loop:
536         replenish(c, rdh);
537         im(c, Irx0);
538         sleep(&c->rrendez, rim, c);
539 loop1:
540         c->rim = 0;
541         if(c->nrd - c->rdfree >= 16)
542                 replenish(c, rdh);
543         r = c->rdba + rdh;
544         if(!(r->status & Rdd))
545                 goto loop;              /* UGH */
546         b = c->rb[rdh];
547         c->rb[rdh] = 0;
548         b->wp += r->length;
549         if((r->status & 1)){
550                 if(r->status & Ipcs)
551                         b->flag |= Bipck;
552                 b->checksum = r->cksum;
553         }
554 //      r->status = 0;
555         etheriq(e, b);
556         c->rdfree--;
557         rdh = Next(rdh, m);
558         goto loop1;                     /* UGH */
559 }
560
561 static void
562 promiscuous(void *a, int on)
563 {
564         Ctlr *c;
565         Ether *e;
566
567         e = a;
568         c = e->ctlr;
569         if(on)
570                 c->reg[Fctrl] |= Upe | Mpe;
571         else
572                 c->reg[Fctrl] &= ~(Upe | Mpe);
573 }
574
575 static void
576 multicast(void *a, uchar *ea, int on)
577 {
578         int b, i;
579         Ctlr *c;
580         Ether *e;
581
582         e = a;
583         c = e->ctlr;
584
585         /*
586          * multiple ether addresses can hash to the same filter bit,
587          * so it's never safe to clear a filter bit.
588          * if we want to clear filter bits, we need to keep track of
589          * all the multicast addresses in use, clear all the filter bits,
590          * then set the ones corresponding to in-use addresses.
591          *
592          *  Extracts the 12 bits, from a multicast address, to determine which
593          *  bit-vector to set in the multicast table. The hardware uses 12 bits, from
594          *  incoming rx multicast addresses, to determine the bit-vector to check in
595          *  the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
596          *  by the MO field of the MCSTCTRL. The MO field is set during initialization
597          *  to mc_filter_type.
598          *
599          * The MTA is a register array of 128 32-bit registers. It is treated
600          * like an array of 4096 bits.  We want to set bit
601          * BitArray[vector_value]. So we figure out what register the bit is
602          * in, read it, OR in the new bit, then write back the new value.  The
603          * register is determined by the upper 7 bits of the vector value and
604          * the bit within that register are determined by the lower 5 bits of
605          * the value.
606          *
607          * when Mcstctrl.Mo == 0, use bits [47:36] of the address
608          * register index = bits [47:41]
609          * which bit in the above register = bits [40:36]
610          */
611         i = ea[5] >> 1;                 /* register index = 47:41 (7 bits) */
612         b = (ea[5]&1)<<4 | ea[4]>>4;    /* which bit in the above register = 40:36 (5 bits) */
613         b = 1 << b;
614         if(on)
615                 c->mta[i] |= b;
616 //      else
617 //              c->mta[i] &= ~b;
618         c->reg[Mta+i] = c->mta[i];
619         c->reg[Mcstctrl] = Mfe;
620         /* for(i = 0; i < 128; i++) c->reg[Mta + i] = -1; brute force it to work for testing */
621 }
622
623 static int
624 detach(Ctlr *c)
625 {
626         int i;
627         u32int l, h;
628
629         l = c->reg[Ral];
630         h = c->reg[Rah];
631         if (h & Av) {
632                 c->ra[0] = l & 0xFF;
633                 c->ra[1] = l>>8 & 0xFF;
634                 c->ra[2] = l>>16 & 0xFF;
635                 c->ra[3] = l>>24 & 0xFF;
636                 c->ra[4] = h & 0xFF;
637                 c->ra[5] = h>>8 & 0xFF;
638         }
639         c->reg[Imc] = ~0;
640         c->reg[Ctrl] |= Rst;
641         for(i = 0; i < 100; i++){
642                 delay(1);
643                 if((c->reg[Ctrl] & Rst) == 0)
644                         break;
645         }
646         if (i >= 100)
647                 return -1;
648         delay(10);
649
650         /* not cleared by reset; kill it manually. */
651         for(i = 1; i < 16; i++)
652                 c->reg[Rah + i] &= ~(1 << 31);
653         for(i = 0; i < 128; i++)
654                 c->reg[Mta + i] = 0;
655         for(i = 1; i < 640; i++)
656                 c->reg[Vfta + i] = 0;
657         c->reg[Ctrlext] &= ~Drvload; /* driver works without this */
658         return 0;
659 }
660
661 static void
662 shutdown(Ether *e)
663 {
664         detach(e->ctlr);
665 }
666
667 static int
668 reset(Ctlr *c)
669 {
670         int i;
671
672         while((c->reg[Eec] & AutoRd) == 0)
673                 ;
674         while((c->reg[Eemngctl] & CfgDone0) == 0)
675                 ;
676         while((c->reg[Eemngctl] & CfgDone1) == 0)
677                 ;
678         while((c->reg[Rdrxctl] & Dmaidone) == 0)
679                 ;
680         if(detach(c)){
681                 print("iX550: reset timeout\n");
682                 return -1;
683         }
684         while((c->reg[Eec] & AutoRd) == 0)
685                 ;
686         while((c->reg[Eemngctl] & CfgDone0) == 0)
687                 ;
688         while((c->reg[Eemngctl] & CfgDone1) == 0)
689                 ;
690         while((c->reg[Rdrxctl] & Dmaidone) == 0)
691                 ;
692         readstats(c);
693         for(i = 0; i<nelem(c->stats); i++)
694                 c->stats[i] = 0;
695
696         /* configure interrupt mapping */
697         c->reg[Ivar] =   Intalloc0 | Intallocval0 | intalloc1 | Intallocval1;
698
699         /* interrupt throttling goes here. */
700         for(i = Itr; i < Itr + 20; i++)
701                 c->reg[i] = 1<<3;       /* 1 interval */
702         return 0;
703 }
704
705 static void
706 txinit(Ctlr *c)
707 {
708         Block *b;
709         int i;
710
711         c->reg[Txdctl] = 16<<Wthresh | 16<<Pthresh;
712         for(i = 0; i < c->ntd; i++){
713                 b = c->tb[i];
714                 c->tb[i] = 0;
715                 if(b)
716                         freeb(b);
717         }
718         memset(c->tdba, 0, c->ntd * sizeof(Td));
719         c->reg[Tdbal] = PCIWADDR(c->tdba);
720         c->reg[Tdbah] = 0;
721         c->reg[Tdlen] = c->ntd*sizeof(Td);
722         c->reg[Tdh] = 0;
723         c->reg[Tdt] = 0;
724         c->tdh = c->ntd - 1;
725         c->tdt = 0;
726
727         c->reg[Txdctl] |= Ten;
728         c->reg[Dmatxctl] |= Txen;
729
730 }
731
732 static void
733 attach(Ether *e)
734 {
735         Ctlr *c;
736         int t;
737         char buf[KNAMELEN];
738
739         c = e->ctlr;
740         c->edev = e;                    /* point back to Ether* */
741         lock(&c->alock);
742         if(c->alloc){
743                 unlock(&c->alock);
744                 return;
745         }
746
747         c->nrd = Nrd;
748         c->ntd = Ntd;
749         t  = c->nrd * sizeof *c->rdba + 255;
750         t += c->ntd * sizeof *c->tdba + 255;
751         t += (c->ntd + c->nrd) * sizeof(Block*);
752         c->alloc = malloc(t);
753         unlock(&c->alock);
754         if(c->alloc == nil)
755                 error(Enomem);
756
757         c->rdba = (Rd*)ROUNDUP((uintptr)c->alloc, 256);
758         c->tdba = (Td*)ROUNDUP((uintptr)(c->rdba + c->nrd), 256);
759         c->rb = (Block**)(c->tdba + c->ntd);
760         c->tb = (Block**)(c->rb + c->nrd);
761
762         rxinit(c);
763         txinit(c);
764
765         c->reg[Ctrlext] |= Drvload; /* driver works without this */
766         snprint(buf, sizeof buf, "#l%dl", e->ctlrno);
767         kproc(buf, lproc, e);
768         snprint(buf, sizeof buf, "#l%dr", e->ctlrno);
769         kproc(buf, rproc, e);
770         snprint(buf, sizeof buf, "#l%dt", e->ctlrno);
771         kproc(buf, tproc, e);
772 }
773
774 static void
775 interrupt(Ureg*, void *v)
776 {
777         int icr, im;
778         Ctlr *c;
779         Ether *e;
780
781         e = v;
782         c = e->ctlr;
783         ilock(&c->imlock);
784         c->reg[Imc] = ~0;
785         im = c->im;
786         while((icr = c->reg[Icr] & c->im) != 0){
787                 if(icr & Lsc){
788                         im &= ~Lsc;
789                         c->lim = icr & Lsc;
790                         wakeup(&c->lrendez);
791                 }
792                 if(icr & Irx0){
793                         im &= ~Irx0;
794                         c->rim = icr & Irx0;
795                         wakeup(&c->rrendez);
796                 }
797                 if(icr & Itx0){
798                         im &= ~Itx0;
799                         c->tim = icr & Itx0;
800                         wakeup(&c->trendez);
801                 }
802         }
803         c->reg[Ims] = c->im = im;
804         iunlock(&c->imlock);
805 }
806
807 extern void addvgaseg(char*, ulong, ulong);
808
809 static void
810 scan(void)
811 {
812         uintptr io, iomsi;
813         void *mem, *memmsi;
814         int pciregs, pcimsix;
815         Ctlr *c;
816         Pcidev *p;
817
818         p = 0;
819         while(p = pcimatch(p, 0x8086, 0x15c8)){ /* X553/X550-AT 10GBASE-T */
820                 pcimsix = 4;
821                 pciregs = 0;
822                 if(nctlr == nelem(ctlrtab)){
823                         print("iX550: too many controllers\n");
824                         return;
825                 }
826                 c = malloc(sizeof *c);
827                 if(c == nil){
828                         print("iX550: can't allocate memory\n");
829                         continue;
830                 }
831                 io = p->mem[pciregs].bar & ~0xf;
832                 mem = vmap(io, p->mem[pciregs].size);
833                 if(mem == nil){
834                         print("iX550: can't map regs %#p\n", io);
835                         free(c);
836                         continue;
837                 }
838                 if (nctlr == 0)
839                         addvgaseg("pci.ctlr0.bar0", p->mem[pciregs].bar & ~0xf, p->mem[pciregs].size);
840                 else if (nctlr == 1)
841                         addvgaseg("pci.ctlr1.bar0", p->mem[pciregs].bar & ~0xf, p->mem[pciregs].size);
842                 iomsi = p->mem[pcimsix].bar & ~0xf;
843                 memmsi = vmap(iomsi, p->mem[pcimsix].size);
844                 if(memmsi == nil){
845                         print("iX550: can't map msi-x regs %#p\n", iomsi);
846                         vunmap(mem, p->mem[pciregs].size);
847                         free(c);
848                         continue;
849                 }
850                 pcienable(p);
851                 c->p = p;
852                 c->io = io;
853                 c->reg = (u32int*)mem;
854                 c->regmsi = (u32int*)memmsi;
855                 c->rbsz = ROUND(Mtu, 1024);
856                 if(reset(c)){
857                         print("iX550: can't reset\n");
858                         free(c);
859                         vunmap(mem, p->mem[pciregs].size);
860                         vunmap(memmsi, p->mem[pcimsix].size);
861                         continue;
862                 }
863                 pcisetbme(p);
864                 ctlrtab[nctlr++] = c;
865         }
866 }
867
868 static int
869 pnp(Ether *e)
870 {
871         static uchar zeros[Eaddrlen];
872         int i;
873         Ctlr *c = nil;
874         uchar *p;
875
876         if(nctlr == 0)
877                 scan();
878         for(i = 0; i < nctlr; i++){
879                 c = ctlrtab[i];
880                 if(c == nil || c->flag & Factive)
881                         continue;
882                 if(e->port == 0 || e->port == c->io)
883                         break;
884         }
885         if (i >= nctlr)
886                 return -1;
887
888         if(memcmp(c->ra, zeros, Eaddrlen) != 0)
889                 memmove(e->ea, c->ra, Eaddrlen);
890
891         p = e->ea;
892         c->reg[Ral] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
893         c->reg[Rah] = p[5]<<8 | p[4] | 1<<31;
894
895         c->flag |= Factive;
896         e->ctlr = c;
897         e->port = (uintptr)c->reg;
898         e->irq = c->p->intl;
899         e->tbdf = c->p->tbdf;
900         e->mbps = 10000;
901         e->maxmtu = Mtu;
902
903         e->arg = e;
904         e->attach = attach;
905         e->ctl = ctl;
906         e->ifstat = ifstat;
907         e->multicast = multicast;
908         e->promiscuous = promiscuous;
909         e->shutdown = shutdown;
910         e->transmit = transmit;
911
912         intrenable(e->irq, interrupt, e, e->tbdf, e->name);
913
914         return 0;
915 }
916
917 void
918 etherx550link(void)
919 {
920         addethercard("iX550", pnp);
921 }