]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherm10g.c
merge
[plan9front.git] / sys / src / 9 / pc / etherm10g.c
1 /*
2  * myricom 10g-pcie-8a 10 Gb ethernet driver
3  * © 2007 erik quanstrom, coraid
4  *
5  * the card is big endian.
6  * we use uvlong rather than uintptr to hold addresses so that
7  * we don't get "warning: stupid shift" on 32-bit architectures.
8  */
9 #include "u.h"
10 #include "../port/lib.h"
11 #include "mem.h"
12 #include "dat.h"
13 #include "fns.h"
14 #include "io.h"
15 #include "../port/error.h"
16 #include "../port/netif.h"
17 #include "../port/etherif.h"
18
19 #ifndef KiB
20 #define KiB             1024u                   /* Kibi 0x0000000000000400 */
21 #define MiB             1048576u                /* Mebi 0x0000000000100000 */
22 #endif /* KiB */
23
24 #define dprint(...)     if(debug) print(__VA_ARGS__)
25 #define pcicapdbg(...)
26 #define malign(n)       mallocalign((n), 4*KiB, 0, 0)
27
28 #include "etherm10g2k.i"
29 #include "etherm10g4k.i"
30
31 static int      debug           = 0;
32 static char     Etimeout[]      = "timeout";
33
34 enum {
35         Epromsz = 256,
36         Maxslots= 1024,
37         Align   = 4096,
38         Maxmtu  = 9000,
39         Noconf  = 0xffffffff,
40
41         Fwoffset= 1*MiB,
42         Cmdoff  = 0xf80000,     /* command port offset */
43         Fwsubmt = 0xfc0000,     /* firmware submission command port offset */
44         Rdmaoff = 0xfc01c0,     /* rdma command port offset */
45 };
46
47 enum {
48         CZero,
49         Creset,
50         Cversion,
51
52         CSintrqdma,     /* issue these before Cetherup */
53         CSbigsz,        /* in bytes bigsize = 2^n */
54         CSsmallsz,
55
56         CGsendoff,
57         CGsmallrxoff,
58         CGbigrxoff,
59         CGirqackoff,
60         CGirqdeassoff,
61         CGsendrgsz,
62         CGrxrgsz,
63
64         CSintrqsz,      /* 2^n */
65         Cetherup,       /* above parameters + mtu/mac addr must be set first. */
66         Cetherdn,
67
68         CSmtu,          /* below may be issued live */
69         CGcoaloff,      /* in µs */
70         CSstatsrate,    /* in µs */
71         CSstatsdma,
72
73         Cpromisc,
74         Cnopromisc,
75         CSmac,
76
77         Cenablefc,
78         Cdisablefc,
79
80         Cdmatest,       /* address in d[0-1], d[2]=length */
81
82         Cenableallmc,
83         Cdisableallmc,
84
85         CSjoinmc,
86         CSleavemc,
87         Cleaveallmc,
88
89         CSstatsdma2,    /* adds (unused) multicast stats */
90 };
91
92 typedef union {
93         uint    i[2];
94         uchar   c[8];
95 } Cmd;
96
97 typedef ulong Slot;
98 typedef struct {
99         ushort  cksum;
100         ushort  len;
101 } Slotparts;
102
103 enum {
104         SFsmall = 1,
105         SFfirst = 2,
106         SFalign = 4,
107         SFnotso = 16,
108 };
109
110 typedef struct {
111         ulong   high;
112         ulong   low;
113         ushort  hdroff;
114         ushort  len;
115         uchar   pad;
116         uchar   nrdma;
117         uchar   chkoff;
118         uchar   flags;
119 } Send;
120
121 typedef struct {
122         QLock;
123         Send    *lanai;         /* tx ring (cksum+len in lanai memory) */
124         Send    *host;          /* tx ring (data in our memory) */
125         Block   **bring;
126 //      uchar   *wcfifo;        /* what the heck is a w/c fifo? */
127         int     size;           /* of buffers in the z8's memory */
128         ulong   segsz;
129         uint    n;              /* rxslots */
130         uint    m;              /* mask; rxslots must be a power of two */
131         uint    i;              /* number of segments (not frames) queued */
132         uint    cnt;            /* number of segments sent by the card */
133
134         ulong   npkt;
135         vlong   nbytes;
136 } Tx;
137
138 typedef struct {
139         Lock;
140         Block   *head;
141         uint    size;           /* buffer size of each block */
142         uint    n;              /* n free buffers */
143         uint    cnt;
144 } Bpool;
145
146 static Bpool    smpool  = { .size = 128, };
147 static Bpool    bgpool  = { .size = Maxmtu, };
148
149 typedef struct {
150         Bpool   *pool;          /* free buffers */
151         ulong   *lanai;         /* rx ring; we have no permanent host shadow */
152         Block   **host;         /* called "info" in myricom driver */
153 //      uchar   *wcfifo;        /* cmd submission fifo */
154         uint    m;
155         uint    n;              /* rxslots */
156         uint    i;
157         uint    cnt;            /* number of buffers allocated (lifetime) */
158         uint    allocfail;
159 } Rx;
160
161 /* dma mapped.  unix network byte order. */
162 typedef struct {
163         uchar   txcnt[4];
164         uchar   linkstat[4];
165         uchar   dlink[4];
166         uchar   derror[4];
167         uchar   drunt[4];
168         uchar   doverrun[4];
169         uchar   dnosm[4];
170         uchar   dnobg[4];
171         uchar   nrdma[4];
172         uchar   txstopped;
173         uchar   down;
174         uchar   updated;
175         uchar   valid;
176 } Stats;
177
178 enum {
179         Detached,
180         Attached,
181         Runed,
182 };
183
184 typedef struct {
185         Slot    *entry;
186         uvlong  busaddr;
187         uint    m;
188         uint    n;
189         uint    i;
190 } Done;
191
192 typedef struct Ctlr Ctlr;
193 typedef struct Ctlr {
194         QLock;
195         uvlong  port;
196         Pcidev* pcidev;
197         Ctlr*   next;
198         int     state;
199         int     kprocs;
200         int     active;
201         int     id;             /* do we need this? */
202
203         uchar   ra[Eaddrlen];
204
205         int     ramsz;
206         uchar   *ram;
207
208         ulong   *irqack;
209         ulong   *irqdeass;
210         ulong   *coal;
211
212         char    eprom[Epromsz];
213         ulong   serial;         /* unit serial number */
214
215         QLock   cmdl;
216         Cmd     *cmd;           /* address of command return */
217         uvlong  cprt;           /* bus address of command */
218
219         uvlong  boot;           /* boot address */
220
221         Done    done;
222         Tx      tx;
223         Rx      sm;
224         Rx      bg;
225         Stats   *stats;
226         uvlong  statsprt;
227
228         Rendez  rxrendez;
229         Rendez  txrendez;
230
231         int     msi;
232         ulong   linkstat;
233         ulong   nrdma;
234 } Ctlr;
235
236 static Ctlr     *ctlrs;
237
238 enum {
239         PciCapPMG        = 0x01,        /* power management */
240         PciCapAGP        = 0x02,
241         PciCapVPD        = 0x03,        /* vital product data */
242         PciCapSID        = 0x04,        /* slot id */
243         PciCapMSI        = 0x05,
244         PciCapCHS        = 0x06,        /* compact pci hot swap */
245         PciCapPCIX       = 0x07,
246         PciCapHTC        = 0x08,        /* hypertransport irq conf */
247         PciCapVND        = 0x09,        /* vendor specific information */
248         PciCapHSW        = 0x0C,        /* hot swap */
249         PciCapPCIe       = 0x10,
250         PciCapMSIX       = 0x11,
251 };
252
253 enum {
254         PcieAERC = 1,
255         PcieVC,
256         PcieSNC,
257         PciePBC,
258 };
259
260 enum {
261         AercCCR = 0x18,         /* control register */
262 };
263
264 enum {
265         PcieCTL = 8,
266         PcieLCR = 12,
267         PcieMRD = 0x7000,       /* maximum read size */
268 };
269
270 static int
271 pcicap(Pcidev *p, int cap)
272 {
273         int i, c, off;
274
275         pcicapdbg("pcicap: %x:%d\n", p->vid, p->did);
276         off = 0x34;                     /* 0x14 for cardbus */
277         for(i = 48; i--; ){
278                 pcicapdbg("\t" "loop %x\n", off);
279                 off = pcicfgr8(p, off);
280                 pcicapdbg("\t" "pcicfgr8 %x\n", off);
281                 if(off < 0x40)
282                         break;
283                 off &= ~3;
284                 c = pcicfgr8(p, off);
285                 pcicapdbg("\t" "pcicfgr8 %x\n", c);
286                 if(c == 0xff)
287                         break;
288                 if(c == cap)
289                         return off;
290                 off++;
291         }
292         return 0;
293 }
294
295 /*
296  * this function doesn't work because pcicgr32 doesn't have access
297  * to the pcie extended configuration space.
298  */
299 static int
300 pciecap(Pcidev *p, int cap)
301 {
302         uint off, i;
303
304         off = 0x100;
305         while(((i = pcicfgr32(p, off)) & 0xffff) != cap){
306                 off = i >> 20;
307                 print("m10g: pciecap offset = %ud",  off);
308                 if(off < 0x100 || off >= 4*KiB - 1)
309                         return 0;
310         }
311         print("m10g: pciecap found = %ud",  off);
312         return off;
313 }
314
315 static int
316 setpcie(Pcidev *p)
317 {
318         int off;
319
320         /* set 4k writes */
321         off = pcicap(p, PciCapPCIe);
322         if(off < 64)
323                 return -1;
324         off += PcieCTL;
325         pcicfgw16(p, off, (pcicfgr16(p, off) & ~PcieMRD) | 5<<12);
326         return 0;
327 }
328
329 static int
330 whichfw(Pcidev *p)
331 {
332         char *s;
333         int i, off, lanes, ecrc;
334         ulong cap;
335
336         /* check the number of configured lanes. */
337         off = pcicap(p, PciCapPCIe);
338         if(off < 64)
339                 return -1;
340         off += PcieLCR;
341         cap = pcicfgr16(p, off);
342         lanes = (cap>>4) & 0x3f;
343
344         /* check AERC register.  we need it on.  */
345         off = pciecap(p, PcieAERC);
346         print("; offset %d returned\n", off);
347         cap = 0;
348         if(off != 0){
349                 off += AercCCR;
350                 cap = pcicfgr32(p, off);
351                 print("m10g: %lud cap\n", cap);
352         }
353         ecrc = (cap>>4) & 0xf;
354         /* if we don't like the aerc, kick it here. */
355
356         print("m10g: %d lanes; ecrc=%d; ", lanes, ecrc);
357         if(s = getconf("myriforce")){
358                 i = strtol(s, 0, 0);
359                 if(i != 4*KiB || i != 2*KiB)
360                         i = 2*KiB;
361                 print("fw = %d [forced]\n", i);
362                 return i;
363         }
364         if(lanes <= 4)
365                 print("fw = 4096 [lanes]\n");
366         else if(ecrc & 10)
367                 print("fw = 4096 [ecrc set]\n");
368         else
369                 print("fw = 4096 [default]\n");
370         return 4*KiB;
371 }
372
373 static int
374 parseeprom(Ctlr *c)
375 {
376         int i, j, k, l, bits;
377         char *s;
378
379         dprint("m10g eprom:\n");
380         s = c->eprom;
381         bits = 3;
382         for(i = 0; s[i] && i < Epromsz; i++){
383                 l = strlen(s+i);
384                 dprint("\t%s\n", s+i);
385                 if(strncmp(s+i, "MAC=", 4) == 0 && l == 4+12+5){
386                         bits ^= 1;
387                         j = i + 4;
388                         for(k = 0; k < 6; k++)
389                                 c->ra[k] = strtoul(s+j+3*k, 0, 16);
390                 }else if(strncmp(s+i, "SN=", 3) == 0){
391                         bits ^= 2;
392                         c->serial = strtoul(s+i+3, 0, 10);
393                 }
394                 i += l;
395         }
396         if(bits)
397                 return -1;
398         return 0;
399 }
400
401 static ushort
402 pbit16(ushort i)
403 {
404         ushort j;
405         uchar *p;
406
407         p = (uchar*)&j;
408         p[1] = i;
409         p[0] = i>>8;
410         return j;
411 }
412
413 static ushort
414 gbit16(uchar i[2])
415 {
416         ushort j;
417
418         j  = i[1];
419         j |= i[0]<<8;
420         return j;
421 }
422
423 static ulong
424 pbit32(ulong i)
425 {
426         ulong j;
427         uchar *p;
428
429         p = (uchar*)&j;
430         p[3] = i;
431         p[2] = i>>8;
432         p[1] = i>>16;
433         p[0] = i>>24;
434         return j;
435 }
436
437 static ulong
438 gbit32(uchar i[4])
439 {
440         ulong j;
441
442         j  = i[3];
443         j |= i[2]<<8;
444         j |= i[1]<<16;
445         j |= i[0]<<24;
446         return j;
447 }
448
449 static void
450 prepcmd(ulong *cmd, int i)
451 {
452         while(i-- > 0)
453                 cmd[i] = pbit32(cmd[i]);
454 }
455
456 /*
457  * the command looks like this (int 32bit integers)
458  * cmd type
459  * addr (low)
460  * addr (high)
461  * pad (used for dma testing)
462  * response (high)
463  * response (low)
464  * 40 byte = 5 int pad.
465  */
466
467 ulong
468 cmd(Ctlr *c, int type, uvlong data)
469 {
470         ulong buf[16], i;
471         Cmd *cmd;
472
473         qlock(&c->cmdl);
474         cmd = c->cmd;
475         cmd->i[1] = Noconf;
476         memset(buf, 0, sizeof buf);
477         buf[0] = type;
478         buf[1] = data;
479         buf[2] = data >> 32;
480         buf[4] = c->cprt >> 32;
481         buf[5] = c->cprt;
482         prepcmd(buf, 6);
483         coherence();
484         memmove(c->ram + Cmdoff, buf, sizeof buf);
485
486         if(waserror())
487                 nexterror();
488         for(i = 0; i < 15; i++){
489                 if(cmd->i[1] != Noconf){
490                         poperror();
491                         i = gbit32(cmd->c);
492                         qunlock(&c->cmdl);
493                         if(cmd->i[1] != 0)
494                                 dprint("[%lux]", i);
495                         return i;
496                 }
497                 tsleep(&up->sleep, return0, 0, 1);
498         }
499         qunlock(&c->cmdl);
500         iprint("m10g: cmd timeout [%ux %ux] cmd=%d\n",
501                 cmd->i[0], cmd->i[1], type);
502         error(Etimeout);
503         return ~0;                      /* silence! */
504 }
505
506 ulong
507 maccmd(Ctlr *c, int type, uchar *m)
508 {
509         ulong buf[16], i;
510         Cmd *cmd;
511
512         qlock(&c->cmdl);
513         cmd = c->cmd;
514         cmd->i[1] = Noconf;
515         memset(buf, 0, sizeof buf);
516         buf[0] = type;
517         buf[1] = m[0]<<24 | m[1]<<16 | m[2]<<8 | m[3];
518         buf[2] = m[4]<< 8 | m[5];
519         buf[4] = c->cprt >> 32;
520         buf[5] = c->cprt;
521         prepcmd(buf, 6);
522         coherence();
523         memmove(c->ram + Cmdoff, buf, sizeof buf);
524
525         if(waserror())
526                 nexterror();
527         for(i = 0; i < 15; i++){
528                 if(cmd->i[1] != Noconf){
529                         poperror();
530                         i = gbit32(cmd->c);
531                         qunlock(&c->cmdl);
532                         if(cmd->i[1] != 0)
533                                 dprint("[%lux]", i);
534                         return i;
535                 }
536                 tsleep(&up->sleep, return0, 0, 1);
537         }
538         qunlock(&c->cmdl);
539         iprint("m10g: maccmd timeout [%ux %ux] cmd=%d\n",
540                 cmd->i[0], cmd->i[1], type);
541         error(Etimeout);
542         return ~0;                      /* silence! */
543 }
544
545 /* remove this garbage after testing */
546 enum {
547         DMAread = 0x10000,
548         DMAwrite= 0x1,
549 };
550
551 ulong
552 dmatestcmd(Ctlr *c, int type, uvlong addr, int len)
553 {
554         ulong buf[16], i;
555
556         memset(buf, 0, sizeof buf);
557         memset(c->cmd, Noconf, sizeof *c->cmd);
558         buf[0] = Cdmatest;
559         buf[1] = addr;
560         buf[2] = addr >> 32;
561         buf[3] = len * type;
562         buf[4] = c->cprt >> 32;
563         buf[5] = c->cprt;
564         prepcmd(buf, 6);
565         coherence();
566         memmove(c->ram + Cmdoff, buf, sizeof buf);
567
568         if(waserror())
569                 nexterror();
570         for(i = 0; i < 15; i++){
571                 if(c->cmd->i[1] != Noconf){
572                         i = gbit32(c->cmd->c);
573                         if(i == 0)
574                                 error(Eio);
575                         poperror();
576                         return i;
577                 }
578                 tsleep(&up->sleep, return0, 0, 5);
579         }
580         error(Etimeout);
581         return ~0;                      /* silence! */
582 }
583
584 ulong
585 rdmacmd(Ctlr *c, int on)
586 {
587         ulong buf[16], i;
588
589         memset(buf, 0, sizeof buf);
590         c->cmd->i[0] = 0;
591         coherence();
592         buf[0] = c->cprt >> 32;
593         buf[1] = c->cprt;
594         buf[2] = Noconf;
595         buf[3] = c->cprt >> 32;
596         buf[4] = c->cprt;
597         buf[5] = on;
598         prepcmd(buf, 6);
599         memmove(c->ram + Rdmaoff, buf, sizeof buf);
600
601         if(waserror())
602                 nexterror();
603         for(i = 0; i < 20; i++){
604                 if(c->cmd->i[0] == Noconf){
605                         poperror();
606                         return gbit32(c->cmd->c);
607                 }
608                 tsleep(&up->sleep, return0, 0, 1);
609         }
610         error(Etimeout);
611         iprint("m10g: rdmacmd timeout\n");
612         return ~0;                      /* silence! */
613 }
614
615 static int
616 loadfw(Ctlr *c, int *align)
617 {
618         ulong *f, *s, sz;
619         int i;
620
621         if((*align = whichfw(c->pcidev)) == 4*KiB){
622                 f = (ulong*)fw4k;
623                 sz = sizeof fw4k;
624         }else{
625                 f = (ulong*)fw2k;
626                 sz = sizeof fw2k;
627         }
628
629         s = (ulong*)(c->ram + Fwoffset);
630         for(i = 0; i < sz / 4; i++)
631                 s[i] = f[i];
632         return sz & ~3;
633 }
634
635 static int
636 bootfw(Ctlr *c)
637 {
638         int i, sz, align;
639         ulong buf[16];
640         Cmd* cmd;
641
642         if((sz = loadfw(c, &align)) == 0)
643                 return 0;
644         dprint("bootfw %d bytes ... ", sz);
645         cmd = c->cmd;
646
647         memset(buf, 0, sizeof buf);
648         c->cmd->i[0] = 0;
649         coherence();
650         buf[0] = c->cprt >> 32; /* upper dma target address */
651         buf[1] = c->cprt;       /* lower */
652         buf[2] = Noconf;        /* writeback */
653         buf[3] = Fwoffset + 8,
654         buf[4] = sz - 8;
655         buf[5] = 8;
656         buf[6] = 0;
657         prepcmd(buf, 7);
658         coherence();
659         memmove(c->ram + Fwsubmt, buf, sizeof buf);
660
661         for(i = 0; i < 20; i++){
662                 if(cmd->i[0] == Noconf)
663                         break;
664                 delay(1);
665         }
666         dprint("[%lux %lux]", gbit32(cmd->c), gbit32(cmd->c+4));
667         if(i == 20){
668                 print("m10g: cannot load fw\n");
669                 return -1;
670         }
671         dprint("\n");
672         c->tx.segsz = align;
673         return 0;
674 }
675
676 static int
677 kickthebaby(Pcidev *p, Ctlr *c)
678 {
679         /* don't kick the baby! */
680         ulong code;
681
682         pcicfgw8(p,  0x10 + c->boot, 0x3);
683         pcicfgw32(p, 0x18 + c->boot, 0xfffffff0);
684         code = pcicfgr32(p, 0x14 + c->boot);
685
686         dprint("reboot status = %lux\n", code);
687         if(code != 0xfffffff0)
688                 return -1;
689         return 0;
690 }
691
692 typedef struct {
693         uchar   len[4];
694         uchar   type[4];
695         char    version[128];
696         uchar   globals[4];
697         uchar   ramsz[4];
698         uchar   specs[4];
699         uchar   specssz[4];
700 } Fwhdr;
701
702 enum {
703         Tmx     = 0x4d582020,
704         Tpcie   = 0x70636965,
705         Teth    = 0x45544820,
706         Tmcp0   = 0x4d435030,
707 };
708
709 static char *
710 fwtype(ulong type)
711 {
712         switch(type){
713         case Tmx:
714                 return "mx";
715         case Tpcie:
716                 return "PCIe";
717         case Teth:
718                 return "eth";
719         case Tmcp0:
720                 return "mcp0";
721         }
722         return "*GOK*";
723 }
724
725 static int
726 chkfw(Ctlr *c)
727 {
728         ulong off, type;
729         Fwhdr *h;
730
731         off = gbit32(c->ram+0x3c);
732         dprint("firmware %lux\n", off);
733         if((off&3) || off + sizeof *h > c->ramsz){
734                 print("!m10g: bad firmware %lux\n", off);
735                 return -1;
736         }
737         h = (Fwhdr*)(c->ram + off);
738         type = gbit32(h->type);
739         dprint("\t" "type       %s\n", fwtype(type));
740         dprint("\t" "vers       %s\n", h->version);
741         dprint("\t" "ramsz      %lux\n", gbit32(h->ramsz));
742         if(type != Teth){
743                 print("!m10g: bad card type %s\n", fwtype(type));
744                 return -1;
745         }
746
747         return bootfw(c) || rdmacmd(c, 0);
748 }
749
750 static int
751 reset(Ether *e, Ctlr *c)
752 {
753         ulong i, sz;
754
755         if(waserror()){
756                 print("m10g: reset error\n");
757                 nexterror();
758                 return -1;
759         }
760
761         chkfw(c);
762         cmd(c, Creset, 0);
763
764         cmd(c, CSintrqsz, c->done.n * sizeof *c->done.entry);
765         cmd(c, CSintrqdma, c->done.busaddr);
766         c->irqack =   (ulong*)(c->ram + cmd(c, CGirqackoff, 0));
767         /* required only if we're not doing msi? */
768         c->irqdeass = (ulong*)(c->ram + cmd(c, CGirqdeassoff, 0));
769         /* this is the driver default, why fiddle with this? */
770         c->coal = (ulong*)(c->ram + cmd(c, CGcoaloff, 0));
771         *c->coal = pbit32(25);
772
773         dprint("dma stats:\n");
774         rdmacmd(c, 1);
775         sz = c->tx.segsz;
776         i = dmatestcmd(c, DMAread, c->done.busaddr, sz);
777         print("m10g: read %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff));
778         i = dmatestcmd(c, DMAwrite, c->done.busaddr, sz);
779         print(" write %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff));
780         i = dmatestcmd(c, DMAwrite|DMAread, c->done.busaddr, sz);
781         print(" r/w %lud MB/s\n", ((i>>16)*sz*2*2) / (i&0xffff));
782         memset(c->done.entry, 0, c->done.n * sizeof *c->done.entry);
783
784         maccmd(c, CSmac, c->ra);
785 //      cmd(c, Cnopromisc, 0);
786         cmd(c, Cenablefc, 0);
787         e->maxmtu = Maxmtu;
788         cmd(c, CSmtu, e->maxmtu);
789         dprint("CSmtu %d...\n", e->maxmtu);
790
791         poperror();
792         return 0;
793 }
794
795 static void
796 ctlrfree(Ctlr *c)
797 {
798         /* free up all the Block*s, too */
799         free(c->tx.host);
800         free(c->sm.host);
801         free(c->bg.host);
802         free(c->cmd);
803         free(c->done.entry);
804         free(c->stats);
805         free(c);
806 }
807
808 static int
809 setmem(Pcidev *p, Ctlr *c)
810 {
811         uvlong raddr;
812         void *mem;
813         Done *d;
814         ulong i;
815
816         c->tx.segsz = 2048;
817         c->ramsz = 2*MiB - (2*48*KiB + 32*KiB) - 0x100;
818         if(c->ramsz > p->mem[0].size)
819                 return -1;
820         if(p->mem[0].bar & 1)
821                 return -1;
822         raddr = p->mem[0].bar & ~0xF;
823         mem = vmap(raddr, p->mem[0].size);
824         if(mem == nil){
825                 print("m10g: can't map %llux\n", raddr);
826                 return -1;
827         }
828         dprint("%llux <- vmap(mem[0].size = %d)\n", raddr, p->mem[0].size);
829         c->port = raddr;
830         c->ram = mem;
831         c->cmd = malign(sizeof *c->cmd);
832         c->cprt = PCIWADDR(c->cmd);
833
834         d = &c->done;
835         d->n = Maxslots;
836         d->m = d->n - 1;
837         i = d->n * sizeof *d->entry;
838         d->entry = malign(i);
839         memset(d->entry, 0, i);
840         d->busaddr = PCIWADDR(d->entry);
841
842         c->stats = malign(sizeof *c->stats);
843         memset(c->stats, 0, sizeof *c->stats);
844         c->statsprt = PCIWADDR(c->stats);
845
846         memmove(c->eprom, c->ram + c->ramsz - Epromsz, Epromsz-2);
847         return setpcie(p) || parseeprom(c);
848 }
849
850 static Rx*
851 whichrx(Ctlr *c, int sz)
852 {
853         if(sz <= smpool.size)
854                 return &c->sm;
855         return &c->bg;
856 }
857
858 static Block*
859 balloc(Rx* rx)
860 {
861         Block *bp;
862
863         ilock(rx->pool);
864         if((bp = rx->pool->head) != nil){
865                 rx->pool->head = bp->next;
866                 bp->next = nil;
867                 rx->pool->n--;
868         }
869         iunlock(rx->pool);
870         return bp;
871 }
872
873 static void
874 rbfree(Block *b, Bpool *p)
875 {
876         b->rp = b->wp = (uchar*)PGROUND((uintptr)b->base);
877         b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
878
879         ilock(p);
880         b->next = p->head;
881         p->head = b;
882         p->n++;
883         p->cnt++;
884         iunlock(p);
885 }
886
887 static void
888 smbfree(Block *b)
889 {
890         rbfree(b, &smpool);
891 }
892
893 static void
894 bgbfree(Block *b)
895 {
896         rbfree(b, &bgpool);
897 }
898
899 static void
900 replenish(Rx *rx)
901 {
902         ulong buf[16], i, idx, e;
903         Bpool *p;
904         Block *b;
905
906         p = rx->pool;
907         if(p->n < 8)
908                 return;
909         memset(buf, 0, sizeof buf);
910         e = (rx->i - rx->cnt) & ~7;
911         e += rx->n;
912         while(p->n >= 8 && e){
913                 idx = rx->cnt & rx->m;
914                 for(i = 0; i < 8; i++){
915                         b = balloc(rx);
916                         buf[i*2]   = pbit32((uvlong)PCIWADDR(b->wp) >> 32);
917                         buf[i*2+1] = pbit32(PCIWADDR(b->wp));
918                         rx->host[idx+i] = b;
919                         assert(b);
920                 }
921                 memmove(rx->lanai + 2*idx, buf, sizeof buf);
922                 coherence();
923                 rx->cnt += 8;
924                 e -= 8;
925         }
926         if(e && p->n > 7+1)
927                 print("m10g: should panic? pool->n = %d", p->n);
928 }
929
930 /*
931  * future:
932  * if (c->mtrr >= 0) {
933  *      c->tx.wcfifo = c->ram+0x200000;
934  *      c->sm.wcfifo = c->ram+0x300000;
935  *      c->bg.wcfifo = c->ram+0x340000;
936  * }
937  */
938
939 static int
940 nextpow(int j)
941 {
942         int i;
943
944         for(i = 0; j > (1 << i); i++)
945                 ;
946         return 1 << i;
947 }
948
949 static void*
950 emalign(int sz)
951 {
952         void *v;
953
954         v = malign(sz);
955         if(v == nil)
956                 error(Enomem);
957         memset(v, 0, sz);
958         return v;
959 }
960
961 static void
962 open0(Ether *e, Ctlr *c)
963 {
964         Block *b;
965         int i, sz, entries;
966
967         entries = cmd(c, CGsendrgsz, 0) / sizeof *c->tx.lanai;
968         c->tx.lanai = (Send*)(c->ram + cmd(c, CGsendoff, 0));
969         c->tx.host  = emalign(entries * sizeof *c->tx.host);
970         c->tx.bring = emalign(entries * sizeof *c->tx.bring);
971         c->tx.n = entries;
972         c->tx.m = entries-1;
973
974         entries = cmd(c, CGrxrgsz, 0)/8;
975         c->sm.pool = &smpool;
976         cmd(c, CSsmallsz, c->sm.pool->size);
977         c->sm.lanai = (ulong*)(c->ram + cmd(c, CGsmallrxoff, 0));
978         c->sm.n = entries;
979         c->sm.m = entries-1;
980         c->sm.host = emalign(entries * sizeof *c->sm.host);
981
982         c->bg.pool = &bgpool;
983         c->bg.pool->size = nextpow(2 + e->maxmtu);  /* 2-byte alignment pad */
984         cmd(c, CSbigsz, c->bg.pool->size);
985         c->bg.lanai = (ulong*)(c->ram + cmd(c, CGbigrxoff, 0));
986         c->bg.n = entries;
987         c->bg.m = entries-1;
988         c->bg.host = emalign(entries * sizeof *c->bg.host);
989
990         sz = c->sm.pool->size + BY2PG;
991         for(i = 0; i < c->sm.n; i++){
992                 if((b = allocb(sz)) == 0)
993                         break;
994                 b->free = smbfree;
995                 freeb(b);
996         }
997         sz = c->bg.pool->size + BY2PG;
998         for(i = 0; i < c->bg.n; i++){
999                 if((b = allocb(sz)) == 0)
1000                         break;
1001                 b->free = bgbfree;
1002                 freeb(b);
1003         }
1004
1005         cmd(c, CSstatsdma, c->statsprt);
1006         c->linkstat = ~0;
1007         c->nrdma = 15;
1008
1009         cmd(c, Cetherup, 0);
1010 }
1011
1012 static Block*
1013 nextblock(Ctlr *c)
1014 {
1015         uint i;
1016         ushort l, k;
1017         Block *b;
1018         Done *d;
1019         Rx *rx;
1020         Slot *s;
1021         Slotparts *sp;
1022
1023         d = &c->done;
1024         s = d->entry;
1025         i = d->i & d->m;
1026         sp = (Slotparts *)(s + i);
1027         l = sp->len;
1028         if(l == 0)
1029                 return 0;
1030         k = sp->cksum;
1031         s[i] = 0;
1032         d->i++;
1033         l = gbit16((uchar*)&l);
1034 //dprint("nextb: i=%d l=%d\n", d->i, l);
1035         rx = whichrx(c, l);
1036         if(rx->i >= rx->cnt){
1037                 iprint("m10g: overrun\n");
1038                 return 0;
1039         }
1040         i = rx->i & rx->m;
1041         b = rx->host[i];
1042         rx->host[i] = 0;
1043         if(b == 0){
1044                 iprint("m10g: error rx to no block.  memory is hosed.\n");
1045                 return 0;
1046         }
1047         rx->i++;
1048
1049         b->flag |= Bipck|Btcpck|Budpck;
1050         b->checksum = k;
1051         b->rp += 2;
1052         b->wp += 2+l;
1053         b->lim = b->wp;                 /* lie like a dog. */
1054         return b;
1055 }
1056
1057 static int
1058 rxcansleep(void *v)
1059 {
1060         Ctlr *c;
1061         Slot *s;
1062         Slotparts *sp;
1063         Done *d;
1064
1065         c = v;
1066         d = &c->done;
1067         s = c->done.entry;
1068         sp = (Slotparts *)(s + (d->i & d->m));
1069         if(sp->len != 0)
1070                 return -1;
1071         c->irqack[0] = pbit32(3);
1072         return 0;
1073 }
1074
1075 static void
1076 m10rx(void *v)
1077 {
1078         Ether *e;
1079         Ctlr *c;
1080         Block *b;
1081
1082         e = v;
1083         c = e->ctlr;
1084         while(waserror())
1085                 ;
1086         for(;;){
1087                 replenish(&c->sm);
1088                 replenish(&c->bg);
1089                 sleep(&c->rxrendez, rxcansleep, c);
1090                 while(b = nextblock(c))
1091                         etheriq(e, b);
1092         }
1093 }
1094
1095 static void
1096 txcleanup(Tx *tx, ulong n)
1097 {
1098         Block *b;
1099         uint j, l, m;
1100
1101         if(tx->npkt == n)
1102                 return;
1103         l = 0;
1104         m = tx->m;
1105         /*
1106          * if tx->cnt == tx->i, yet tx->npkt == n-1, we just
1107          * caught ourselves and myricom card updating.
1108          */
1109         for(;; tx->cnt++){
1110                 j = tx->cnt & tx->m;
1111                 if(b = tx->bring[j]){
1112                         tx->bring[j] = 0;
1113                         tx->nbytes += BLEN(b);
1114                         freeb(b);
1115                         if(++tx->npkt == n)
1116                                 return;
1117                 }
1118                 if(tx->cnt == tx->i)
1119                         return;
1120                 if(l++ == m){
1121                         iprint("m10g: tx ovrun: %lud %lud\n", n, tx->npkt);
1122                         return;
1123                 }
1124         }
1125 }
1126
1127 static int
1128 txcansleep(void *v)
1129 {
1130         Ctlr *c;
1131
1132         c = v;
1133         if(c->tx.cnt != c->tx.i && c->tx.npkt != gbit32(c->stats->txcnt))
1134                 return -1;
1135         return 0;
1136 }
1137
1138 static void
1139 txproc(void *v)
1140 {
1141         Ether *e;
1142         Ctlr *c;
1143         Tx *tx;
1144
1145         e = v;
1146         c = e->ctlr;
1147         tx = &c->tx;
1148         while(waserror())
1149                 ;
1150         for(;;){
1151                 sleep(&c->txrendez, txcansleep, c);
1152                 txcleanup(tx, gbit32(c->stats->txcnt));
1153         }
1154 }
1155
1156 static void
1157 submittx(Tx *tx, int n)
1158 {
1159         Send *l, *h;
1160         int i0, i, m;
1161
1162         m = tx->m;
1163         i0 = tx->i & m;
1164         l = tx->lanai;
1165         h = tx->host;
1166         for(i = n-1; i >= 0; i--)
1167                 memmove(l+(i + i0 & m), h+(i + i0 & m), sizeof *h);
1168         tx->i += n;
1169 //      coherence();
1170 }
1171
1172 static int
1173 nsegments(Block *b, int segsz)
1174 {
1175         uintptr bus, end, slen, len;
1176         int i;
1177
1178         bus = PCIWADDR(b->rp);
1179         i = 0;
1180         for(len = BLEN(b); len; len -= slen){
1181                 end = bus + segsz & ~(segsz-1);
1182                 slen = end - bus;
1183                 if(slen > len)
1184                         slen = len;
1185                 bus += slen;
1186                 i++;
1187         }
1188         return i;
1189 }
1190
1191 static void
1192 m10gtransmit(Ether *e)
1193 {
1194         ushort slen;
1195         ulong i, cnt, rdma, nseg, count, end, bus, len, segsz;
1196         uchar flags;
1197         Block *b;
1198         Ctlr *c;
1199         Send *s, *s0, *s0m8;
1200         Tx *tx;
1201
1202         c = e->ctlr;
1203         tx = &c->tx;
1204         segsz = tx->segsz;
1205
1206         qlock(tx);
1207         count = 0;
1208         s = tx->host + (tx->i & tx->m);
1209         cnt = tx->cnt;
1210         s0 =   tx->host + (cnt & tx->m);
1211         s0m8 = tx->host + ((cnt - 8) & tx->m);
1212         i = tx->i;
1213         for(; s >= s0 || s < s0m8; i += nseg){
1214                 if((b = qget(e->oq)) == nil)
1215                         break;
1216                 flags = SFfirst|SFnotso;
1217                 if((len = BLEN(b)) < 1520)
1218                         flags |= SFsmall;
1219                 rdma = nseg = nsegments(b, segsz);
1220                 bus = PCIWADDR(b->rp);
1221                 for(; len; len -= slen){
1222                         end = (bus + segsz) & ~(segsz-1);
1223                         slen = end - bus;
1224                         if(slen > len)
1225                                 slen = len;
1226                         s->low = pbit32(bus);
1227                         s->len = pbit16(slen);
1228                         s->nrdma = rdma;
1229                         s->flags = flags;
1230
1231                         bus += slen;
1232                         if(++s ==  tx->host + tx->n)
1233                                 s = tx->host;
1234                         count++;
1235                         flags &= ~SFfirst;
1236                         rdma = 1;
1237                 }
1238                 tx->bring[(i + nseg - 1) & tx->m] = b;
1239                 if(1 || count > 0){
1240                         submittx(tx, count);
1241                         count = 0;
1242                         cnt = tx->cnt;
1243                         s0 =   tx->host + (cnt & tx->m);
1244                         s0m8 = tx->host + ((cnt - 8) & tx->m);
1245                 }
1246         }
1247         qunlock(tx);
1248 }
1249
1250 static void
1251 checkstats(Ether *e, Ctlr *c, Stats *s)
1252 {
1253         ulong i;
1254
1255         if(s->updated == 0)
1256                 return;
1257
1258         i = gbit32(s->linkstat);
1259         if(c->linkstat != i){
1260                 e->link = i;
1261                 if(c->linkstat = i)
1262                         dprint("m10g: link up\n");
1263                 else
1264                         dprint("m10g: link down\n");
1265         }
1266         i = gbit32(s->nrdma);
1267         if(i != c->nrdma){
1268                 dprint("m10g: rdma timeout %ld\n", i);
1269                 c->nrdma = i;
1270         }
1271 }
1272
1273 static void
1274 waitintx(Ctlr *c)
1275 {
1276         int i;
1277
1278         for(i = 0; i < 1024*1024; i++){
1279                 if(c->stats->valid == 0)
1280                         break;
1281                 coherence();
1282         }
1283 }
1284
1285 static void
1286 m10ginterrupt(Ureg *, void *v)
1287 {
1288         Ether *e;
1289         Ctlr *c;
1290
1291         e = v;
1292         c = e->ctlr;
1293
1294         if(c->state != Runed || c->stats->valid == 0)   /* not ready for us? */
1295                 return;
1296
1297         if(c->stats->valid & 1)
1298                 wakeup(&c->rxrendez);
1299         if(gbit32(c->stats->txcnt) != c->tx.npkt)
1300                 wakeup(&c->txrendez);
1301         if(c->msi == 0)
1302                 *c->irqdeass = 0;
1303         else
1304                 c->stats->valid = 0;
1305         waitintx(c);
1306         checkstats(e, c, c->stats);
1307         c->irqack[1] = pbit32(3);
1308 }
1309
1310 static void
1311 m10gattach(Ether *e)
1312 {
1313         Ctlr *c;
1314         char name[12];
1315
1316         dprint("m10gattach\n");
1317
1318         qlock(e->ctlr);
1319         c = e->ctlr;
1320         if(c->state != Detached){
1321                 qunlock(c);
1322                 return;
1323         }
1324         if(waserror()){
1325                 c->state = Detached;
1326                 qunlock(c);
1327                 nexterror();
1328         }
1329         reset(e, c);
1330         c->state = Attached;
1331         open0(e, c);
1332         if(c->kprocs == 0){
1333                 c->kprocs++;
1334                 snprint(name, sizeof name, "#l%drxproc", e->ctlrno);
1335                 kproc(name, m10rx, e);
1336                 snprint(name, sizeof name, "#l%dtxproc", e->ctlrno);
1337                 kproc(name, txproc, e);
1338         }
1339         c->state = Runed;
1340         qunlock(c);
1341         poperror();
1342 }
1343
1344 static int
1345 m10gdetach(Ctlr *c)
1346 {
1347         dprint("m10gdetach\n");
1348 //      reset(e->ctlr);
1349         vunmap(c->ram, c->pcidev->mem[0].size);
1350         ctlrfree(c);
1351         return -1;
1352 }
1353
1354 static int
1355 lstcount(Block *b)
1356 {
1357         int i;
1358
1359         i = 0;
1360         for(; b; b = b->next)
1361                 i++;
1362         return i;
1363 }
1364
1365 static long
1366 m10gifstat(Ether *e, void *v, long n, ulong off)
1367 {
1368         char *p;
1369         Ctlr *c;
1370         Stats s;
1371
1372         c = e->ctlr;
1373         p = smalloc(READSTR);
1374         /* no point in locking this because this is done via dma. */
1375         memmove(&s, c->stats, sizeof s);
1376         snprint(p, READSTR,
1377                 "txcnt = %lud\n"  "linkstat = %lud\n"   "dlink = %lud\n"
1378                 "derror = %lud\n" "drunt = %lud\n"      "doverrun = %lud\n"
1379                 "dnosm = %lud\n"  "dnobg = %lud\n"      "nrdma = %lud\n"
1380                 "txstopped = %ud\n" "down = %ud\n"      "updated = %ud\n"
1381                 "valid = %ud\n\n"
1382                 "tx pkt = %lud\n"  "tx bytes = %lld\n"
1383                 "tx cnt = %ud\n"  "tx n = %ud\n"        "tx i = %ud\n"
1384                 "sm cnt = %ud\n"  "sm i = %ud\n"        "sm n = %ud\n"
1385                 "sm lst = %ud\n"
1386                 "bg cnt = %ud\n"  "bg i = %ud\n"        "bg n = %ud\n"
1387                 "bg lst = %ud\n"
1388                 "segsz = %lud\n"   "coal = %lud\n",
1389                 gbit32(s.txcnt),  gbit32(s.linkstat),   gbit32(s.dlink),
1390                 gbit32(s.derror), gbit32(s.drunt),      gbit32(s.doverrun),
1391                 gbit32(s.dnosm),  gbit32(s.dnobg),      gbit32(s.nrdma),
1392                 s.txstopped,  s.down, s.updated, s.valid,
1393                 c->tx.npkt, c->tx.nbytes,
1394                 c->tx.cnt, c->tx.n, c->tx.i,
1395                 c->sm.cnt, c->sm.i, c->sm.pool->n, lstcount(c->sm.pool->head),
1396                 c->bg.cnt, c->bg.i, c->bg.pool->n, lstcount(c->bg.pool->head),
1397                 c->tx.segsz, gbit32((uchar*)c->coal));
1398
1399         n = readstr(off, v, n, p);
1400         free(p);
1401         return n;
1402 }
1403
1404 //static void
1405 //summary(Ether *e)
1406 //{
1407 //      char *buf;
1408 //      int n, i, j;
1409 //
1410 //      if(e == 0)
1411 //              return;
1412 //      buf = malloc(n=250);
1413 //      if(buf == 0)
1414 //              return;
1415 //
1416 //      snprint(buf, n, "oq\n");
1417 //      qsummary(e->oq, buf+3, n-3-1);
1418 //      iprint("%s", buf);
1419 //
1420 //      if(e->f) for(i = 0; e->f[i]; i++){
1421 //              j = snprint(buf, n, "f%d %d\n", i, e->f[i]->type);
1422 //              qsummary(e->f[i]->in, buf+j, n-j-1);
1423 //              print("%s", buf);
1424 //      }
1425 //
1426 //      free(buf);
1427 //}
1428
1429 static void
1430 rxring(Ctlr *c)
1431 {
1432         Done *d;
1433         Slot *s;
1434         Slotparts *sp;
1435         int i;
1436
1437         d = &c->done;
1438         s = d->entry;
1439         for(i = 0; i < d->n; i++) {
1440                 sp = (Slotparts *)(s + i);
1441                 if(sp->len)
1442                         iprint("s[%d] = %d\n", i, sp->len);
1443         }
1444 }
1445
1446 enum {
1447         CMdebug,
1448         CMcoal,
1449         CMwakeup,
1450         CMtxwakeup,
1451         CMqsummary,
1452         CMrxring,
1453 };
1454
1455 static Cmdtab ctab[] = {
1456         CMdebug,        "debug",        2,
1457         CMcoal,         "coal",         2,
1458         CMwakeup,       "wakeup",       1,
1459         CMtxwakeup,     "txwakeup",     1,
1460 //      CMqsummary,     "q",            1,
1461         CMrxring,       "rxring",       1,
1462 };
1463
1464 static long
1465 m10gctl(Ether *e, void *v, long n)
1466 {
1467         int i;
1468         Cmdbuf *c;
1469         Cmdtab *t;
1470
1471         dprint("m10gctl\n");
1472         if(e->ctlr == nil)
1473                 error(Enonexist);
1474
1475         c = parsecmd(v, n);
1476         if(waserror()){
1477                 free(c);
1478                 nexterror();
1479         }
1480         t = lookupcmd(c, ctab, nelem(ctab));
1481         switch(t->index){
1482         case CMdebug:
1483                 debug = (strcmp(c->f[1], "on") == 0);
1484                 break;
1485         case CMcoal:
1486                 i = atoi(c->f[1]);
1487                 if(i < 0 || i > 1000)
1488                         error(Ebadarg);
1489                 *((Ctlr*)e->ctlr)->coal = pbit32(i);
1490                 break;
1491         case CMwakeup:
1492                 wakeup(&((Ctlr*)e->ctlr)->rxrendez); /* you're kidding, right? */
1493                 break;
1494         case CMtxwakeup:
1495                 wakeup(&((Ctlr*)e->ctlr)->txrendez); /* you're kidding, right? */
1496                 break;
1497 //      case CMqsummary:
1498 //              summary(e);
1499 //              break;
1500         case CMrxring:
1501                 rxring(e->ctlr);
1502                 break;
1503         default:
1504                 error(Ebadarg);
1505         }
1506         free(c);
1507         poperror();
1508         return n;
1509 }
1510
1511 static void
1512 m10gshutdown(Ether *e)
1513 {
1514         dprint("m10gshutdown\n");
1515         m10gdetach(e->ctlr);
1516 }
1517
1518 static void
1519 m10gpromiscuous(void *v, int on)
1520 {
1521         Ether *e;
1522         int i;
1523
1524         dprint("m10gpromiscuous\n");
1525         e = v;
1526         if(on)
1527                 i = Cpromisc;
1528         else
1529                 i = Cnopromisc;
1530         cmd(e->ctlr, i, 0);
1531 }
1532
1533 static int      mcctab[]  = { CSleavemc, CSjoinmc };
1534 static char     *mcntab[] = { "leave", "join" };
1535
1536 static void
1537 m10gmulticast(void *v, uchar *ea, int on)
1538 {
1539         Ether *e;
1540         int i;
1541
1542         dprint("m10gmulticast\n");
1543         e = v;
1544         if((i = maccmd(e->ctlr, mcctab[on], ea)) != 0)
1545                 print("m10g: can't %s %E: %d\n", mcntab[on], ea, i);
1546 }
1547
1548 static void
1549 m10gpci(void)
1550 {
1551         Pcidev *p;
1552         Ctlr *t, *c;
1553
1554         t = 0;
1555         for(p = 0; p = pcimatch(p, Vmyricom, 0); ){
1556                 switch(p->did){
1557                 case 0x8:               /* 8a */
1558                         break;
1559                 case 0x9:               /* 8a with msi-x fw */
1560                 case 0xa:               /* 8b */
1561                 case 0xb:               /* 8b2 */
1562                 case 0xc:               /* 2-8b2 */
1563                         /* untested */
1564                         break;
1565                 default:
1566                         print("etherm10g: unknown myricom did %#ux\n", p->did);
1567                         continue;
1568                 }
1569                 c = malloc(sizeof *c);
1570                 if(c == nil){
1571                         print("etherm10g: can't allocate memory\n");
1572                         continue;
1573                 }
1574                 c->pcidev = p;
1575                 pcienable(p);
1576                 c->id = p->did<<16 | p->vid;
1577                 c->boot = pcicap(p, PciCapVND);
1578 //              kickthebaby(p, c);
1579                 pcisetbme(p);
1580                 if(setmem(p, c) == -1){
1581                         print("m10g: setmem failed\n");
1582                         free(c);
1583                         /* cleanup */
1584                         continue;
1585                 }
1586                 if(t)
1587                         t->next = c;
1588                 else
1589                         ctlrs = c;
1590                 t = c;
1591         }
1592 }
1593
1594 static int
1595 m10gpnp(Ether *e)
1596 {
1597         Ctlr *c;
1598
1599         if(ctlrs == nil)
1600                 m10gpci();
1601
1602         for(c = ctlrs; c != nil; c = c->next)
1603                 if(c->active)
1604                         continue;
1605                 else if(e->port == 0 || e->port == c->port)
1606                         break;
1607         if(c == nil)
1608                 return -1;
1609         c->active = 1;
1610
1611         e->ctlr = c;
1612         e->port = c->port;
1613         e->irq = c->pcidev->intl;
1614         e->tbdf = c->pcidev->tbdf;
1615         e->mbps = 10000;
1616         memmove(e->ea, c->ra, Eaddrlen);
1617
1618         e->attach = m10gattach;
1619         e->transmit = m10gtransmit;
1620         e->interrupt = m10ginterrupt;
1621         e->ifstat = m10gifstat;
1622         e->ctl = m10gctl;
1623 //      e->power = m10gpower;
1624         e->shutdown = m10gshutdown;
1625
1626         e->arg = e;
1627         e->promiscuous = m10gpromiscuous;
1628         e->multicast = m10gmulticast;
1629
1630         return 0;
1631 }
1632
1633 void
1634 etherm10glink(void)
1635 {
1636         addethercard("m10g", m10gpnp);
1637 }