]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherm10g.c
cfcdf6256b7de63c1ef8e67542d645faecb115a3
[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         int     state;
196         int     kprocs;
197         uvlong  port;
198         Pcidev* pcidev;
199         Ctlr*   next;
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         ulong i;
812         uvlong raddr;
813         Done *d;
814         void *mem;
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
821         raddr = p->mem[0].bar & ~0x0F;
822         mem = vmap(raddr, p->mem[0].size);
823         if(mem == nil){
824                 print("m10g: can't map %8.8lux\n", p->mem[0].bar);
825                 return -1;
826         }
827         dprint("%llux <- vmap(mem[0].size = %ux)\n", raddr, p->mem[0].size);
828         c->port = raddr;
829         c->ram = mem;
830         c->cmd = malign(sizeof *c->cmd);
831         c->cprt = PCIWADDR(c->cmd);
832
833         d = &c->done;
834         d->n = Maxslots;
835         d->m = d->n - 1;
836         i = d->n * sizeof *d->entry;
837         d->entry = malign(i);
838         memset(d->entry, 0, i);
839         d->busaddr = PCIWADDR(d->entry);
840
841         c->stats = malign(sizeof *c->stats);
842         memset(c->stats, 0, sizeof *c->stats);
843         c->statsprt = PCIWADDR(c->stats);
844
845         memmove(c->eprom, c->ram + c->ramsz - Epromsz, Epromsz-2);
846         return setpcie(p) || parseeprom(c);
847 }
848
849 static Rx*
850 whichrx(Ctlr *c, int sz)
851 {
852         if(sz <= smpool.size)
853                 return &c->sm;
854         return &c->bg;
855 }
856
857 static Block*
858 balloc(Rx* rx)
859 {
860         Block *bp;
861
862         ilock(rx->pool);
863         if((bp = rx->pool->head) != nil){
864                 rx->pool->head = bp->next;
865                 bp->next = nil;
866                 rx->pool->n--;
867         }
868         iunlock(rx->pool);
869         return bp;
870 }
871
872 static void
873 rbfree(Block *b, Bpool *p)
874 {
875         b->rp = b->wp = (uchar*)PGROUND((uintptr)b->base);
876         b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
877
878         ilock(p);
879         b->next = p->head;
880         p->head = b;
881         p->n++;
882         p->cnt++;
883         iunlock(p);
884 }
885
886 static void
887 smbfree(Block *b)
888 {
889         rbfree(b, &smpool);
890 }
891
892 static void
893 bgbfree(Block *b)
894 {
895         rbfree(b, &bgpool);
896 }
897
898 static void
899 replenish(Rx *rx)
900 {
901         ulong buf[16], i, idx, e;
902         Bpool *p;
903         Block *b;
904
905         p = rx->pool;
906         if(p->n < 8)
907                 return;
908         memset(buf, 0, sizeof buf);
909         e = (rx->i - rx->cnt) & ~7;
910         e += rx->n;
911         while(p->n >= 8 && e){
912                 idx = rx->cnt & rx->m;
913                 for(i = 0; i < 8; i++){
914                         b = balloc(rx);
915                         buf[i*2]   = pbit32((uvlong)PCIWADDR(b->wp) >> 32);
916                         buf[i*2+1] = pbit32(PCIWADDR(b->wp));
917                         rx->host[idx+i] = b;
918                         assert(b);
919                 }
920                 memmove(rx->lanai + 2*idx, buf, sizeof buf);
921                 coherence();
922                 rx->cnt += 8;
923                 e -= 8;
924         }
925         if(e && p->n > 7+1)
926                 print("m10g: should panic? pool->n = %d", p->n);
927 }
928
929 /*
930  * future:
931  * if (c->mtrr >= 0) {
932  *      c->tx.wcfifo = c->ram+0x200000;
933  *      c->sm.wcfifo = c->ram+0x300000;
934  *      c->bg.wcfifo = c->ram+0x340000;
935  * }
936  */
937
938 static int
939 nextpow(int j)
940 {
941         int i;
942
943         for(i = 0; j > (1 << i); i++)
944                 ;
945         return 1 << i;
946 }
947
948 static void*
949 emalign(int sz)
950 {
951         void *v;
952
953         v = malign(sz);
954         if(v == nil)
955                 error(Enomem);
956         memset(v, 0, sz);
957         return v;
958 }
959
960 static void
961 open0(Ether *e, Ctlr *c)
962 {
963         Block *b;
964         int i, sz, entries;
965
966         entries = cmd(c, CGsendrgsz, 0) / sizeof *c->tx.lanai;
967         c->tx.lanai = (Send*)(c->ram + cmd(c, CGsendoff, 0));
968         c->tx.host  = emalign(entries * sizeof *c->tx.host);
969         c->tx.bring = emalign(entries * sizeof *c->tx.bring);
970         c->tx.n = entries;
971         c->tx.m = entries-1;
972
973         entries = cmd(c, CGrxrgsz, 0)/8;
974         c->sm.pool = &smpool;
975         cmd(c, CSsmallsz, c->sm.pool->size);
976         c->sm.lanai = (ulong*)(c->ram + cmd(c, CGsmallrxoff, 0));
977         c->sm.n = entries;
978         c->sm.m = entries-1;
979         c->sm.host = emalign(entries * sizeof *c->sm.host);
980
981         c->bg.pool = &bgpool;
982         c->bg.pool->size = nextpow(2 + e->maxmtu);  /* 2-byte alignment pad */
983         cmd(c, CSbigsz, c->bg.pool->size);
984         c->bg.lanai = (ulong*)(c->ram + cmd(c, CGbigrxoff, 0));
985         c->bg.n = entries;
986         c->bg.m = entries-1;
987         c->bg.host = emalign(entries * sizeof *c->bg.host);
988
989         sz = c->sm.pool->size + BY2PG;
990         for(i = 0; i < c->sm.n; i++){
991                 if((b = allocb(sz)) == 0)
992                         break;
993                 b->free = smbfree;
994                 freeb(b);
995         }
996         sz = c->bg.pool->size + BY2PG;
997         for(i = 0; i < c->bg.n; i++){
998                 if((b = allocb(sz)) == 0)
999                         break;
1000                 b->free = bgbfree;
1001                 freeb(b);
1002         }
1003
1004         cmd(c, CSstatsdma, c->statsprt);
1005         c->linkstat = ~0;
1006         c->nrdma = 15;
1007
1008         cmd(c, Cetherup, 0);
1009 }
1010
1011 static Block*
1012 nextblock(Ctlr *c)
1013 {
1014         uint i;
1015         ushort l, k;
1016         Block *b;
1017         Done *d;
1018         Rx *rx;
1019         Slot *s;
1020         Slotparts *sp;
1021
1022         d = &c->done;
1023         s = d->entry;
1024         i = d->i & d->m;
1025         sp = (Slotparts *)(s + i);
1026         l = sp->len;
1027         if(l == 0)
1028                 return 0;
1029         k = sp->cksum;
1030         s[i] = 0;
1031         d->i++;
1032         l = gbit16((uchar*)&l);
1033 //dprint("nextb: i=%d l=%d\n", d->i, l);
1034         rx = whichrx(c, l);
1035         if(rx->i >= rx->cnt){
1036                 iprint("m10g: overrun\n");
1037                 return 0;
1038         }
1039         i = rx->i & rx->m;
1040         b = rx->host[i];
1041         rx->host[i] = 0;
1042         if(b == 0){
1043                 iprint("m10g: error rx to no block.  memory is hosed.\n");
1044                 return 0;
1045         }
1046         rx->i++;
1047
1048         b->flag |= Bipck|Btcpck|Budpck;
1049         b->checksum = k;
1050         b->rp += 2;
1051         b->wp += 2+l;
1052         b->lim = b->wp;                 /* lie like a dog. */
1053         return b;
1054 }
1055
1056 static int
1057 rxcansleep(void *v)
1058 {
1059         Ctlr *c;
1060         Slot *s;
1061         Slotparts *sp;
1062         Done *d;
1063
1064         c = v;
1065         d = &c->done;
1066         s = c->done.entry;
1067         sp = (Slotparts *)(s + (d->i & d->m));
1068         if(sp->len != 0)
1069                 return -1;
1070         c->irqack[0] = pbit32(3);
1071         return 0;
1072 }
1073
1074 static void
1075 m10rx(void *v)
1076 {
1077         Ether *e;
1078         Ctlr *c;
1079         Block *b;
1080
1081         e = v;
1082         c = e->ctlr;
1083         while(waserror())
1084                 ;
1085         for(;;){
1086                 replenish(&c->sm);
1087                 replenish(&c->bg);
1088                 sleep(&c->rxrendez, rxcansleep, c);
1089                 while(b = nextblock(c))
1090                         etheriq(e, b);
1091         }
1092 }
1093
1094 static void
1095 txcleanup(Tx *tx, ulong n)
1096 {
1097         Block *b;
1098         uint j, l, m;
1099
1100         if(tx->npkt == n)
1101                 return;
1102         l = 0;
1103         m = tx->m;
1104         /*
1105          * if tx->cnt == tx->i, yet tx->npkt == n-1, we just
1106          * caught ourselves and myricom card updating.
1107          */
1108         for(;; tx->cnt++){
1109                 j = tx->cnt & tx->m;
1110                 if(b = tx->bring[j]){
1111                         tx->bring[j] = 0;
1112                         tx->nbytes += BLEN(b);
1113                         freeb(b);
1114                         if(++tx->npkt == n)
1115                                 return;
1116                 }
1117                 if(tx->cnt == tx->i)
1118                         return;
1119                 if(l++ == m){
1120                         iprint("m10g: tx ovrun: %lud %lud\n", n, tx->npkt);
1121                         return;
1122                 }
1123         }
1124 }
1125
1126 static int
1127 txcansleep(void *v)
1128 {
1129         Ctlr *c;
1130
1131         c = v;
1132         if(c->tx.cnt != c->tx.i && c->tx.npkt != gbit32(c->stats->txcnt))
1133                 return -1;
1134         return 0;
1135 }
1136
1137 static void
1138 txproc(void *v)
1139 {
1140         Ether *e;
1141         Ctlr *c;
1142         Tx *tx;
1143
1144         e = v;
1145         c = e->ctlr;
1146         tx = &c->tx;
1147         while(waserror())
1148                 ;
1149         for(;;){
1150                 sleep(&c->txrendez, txcansleep, c);
1151                 txcleanup(tx, gbit32(c->stats->txcnt));
1152         }
1153 }
1154
1155 static void
1156 submittx(Tx *tx, int n)
1157 {
1158         Send *l, *h;
1159         int i0, i, m;
1160
1161         m = tx->m;
1162         i0 = tx->i & m;
1163         l = tx->lanai;
1164         h = tx->host;
1165         for(i = n-1; i >= 0; i--)
1166                 memmove(l+(i + i0 & m), h+(i + i0 & m), sizeof *h);
1167         tx->i += n;
1168 //      coherence();
1169 }
1170
1171 static int
1172 nsegments(Block *b, int segsz)
1173 {
1174         uintptr bus, end, slen, len;
1175         int i;
1176
1177         bus = PCIWADDR(b->rp);
1178         i = 0;
1179         for(len = BLEN(b); len; len -= slen){
1180                 end = bus + segsz & ~(segsz-1);
1181                 slen = end - bus;
1182                 if(slen > len)
1183                         slen = len;
1184                 bus += slen;
1185                 i++;
1186         }
1187         return i;
1188 }
1189
1190 static void
1191 m10gtransmit(Ether *e)
1192 {
1193         ushort slen;
1194         ulong i, cnt, rdma, nseg, count, end, bus, len, segsz;
1195         uchar flags;
1196         Block *b;
1197         Ctlr *c;
1198         Send *s, *s0, *s0m8;
1199         Tx *tx;
1200
1201         c = e->ctlr;
1202         tx = &c->tx;
1203         segsz = tx->segsz;
1204
1205         qlock(tx);
1206         count = 0;
1207         s = tx->host + (tx->i & tx->m);
1208         cnt = tx->cnt;
1209         s0 =   tx->host + (cnt & tx->m);
1210         s0m8 = tx->host + ((cnt - 8) & tx->m);
1211         i = tx->i;
1212         for(; s >= s0 || s < s0m8; i += nseg){
1213                 if((b = qget(e->oq)) == nil)
1214                         break;
1215                 flags = SFfirst|SFnotso;
1216                 if((len = BLEN(b)) < 1520)
1217                         flags |= SFsmall;
1218                 rdma = nseg = nsegments(b, segsz);
1219                 bus = PCIWADDR(b->rp);
1220                 for(; len; len -= slen){
1221                         end = (bus + segsz) & ~(segsz-1);
1222                         slen = end - bus;
1223                         if(slen > len)
1224                                 slen = len;
1225                         s->low = pbit32(bus);
1226                         s->len = pbit16(slen);
1227                         s->nrdma = rdma;
1228                         s->flags = flags;
1229
1230                         bus += slen;
1231                         if(++s ==  tx->host + tx->n)
1232                                 s = tx->host;
1233                         count++;
1234                         flags &= ~SFfirst;
1235                         rdma = 1;
1236                 }
1237                 tx->bring[(i + nseg - 1) & tx->m] = b;
1238                 if(1 || count > 0){
1239                         submittx(tx, count);
1240                         count = 0;
1241                         cnt = tx->cnt;
1242                         s0 =   tx->host + (cnt & tx->m);
1243                         s0m8 = tx->host + ((cnt - 8) & tx->m);
1244                 }
1245         }
1246         qunlock(tx);
1247 }
1248
1249 static void
1250 checkstats(Ether *e, Ctlr *c, Stats *s)
1251 {
1252         ulong i;
1253
1254         if(s->updated == 0)
1255                 return;
1256
1257         i = gbit32(s->linkstat);
1258         if(c->linkstat != i){
1259                 e->link = i;
1260                 if(c->linkstat = i)
1261                         dprint("m10g: link up\n");
1262                 else
1263                         dprint("m10g: link down\n");
1264         }
1265         i = gbit32(s->nrdma);
1266         if(i != c->nrdma){
1267                 dprint("m10g: rdma timeout %ld\n", i);
1268                 c->nrdma = i;
1269         }
1270 }
1271
1272 static void
1273 waitintx(Ctlr *c)
1274 {
1275         int i;
1276
1277         for(i = 0; i < 1024*1024; i++){
1278                 if(c->stats->valid == 0)
1279                         break;
1280                 coherence();
1281         }
1282 }
1283
1284 static void
1285 m10ginterrupt(Ureg *, void *v)
1286 {
1287         Ether *e;
1288         Ctlr *c;
1289
1290         e = v;
1291         c = e->ctlr;
1292
1293         if(c->state != Runed || c->stats->valid == 0)   /* not ready for us? */
1294                 return;
1295
1296         if(c->stats->valid & 1)
1297                 wakeup(&c->rxrendez);
1298         if(gbit32(c->stats->txcnt) != c->tx.npkt)
1299                 wakeup(&c->txrendez);
1300         if(c->msi == 0)
1301                 *c->irqdeass = 0;
1302         else
1303                 c->stats->valid = 0;
1304         waitintx(c);
1305         checkstats(e, c, c->stats);
1306         c->irqack[1] = pbit32(3);
1307 }
1308
1309 static void
1310 m10gattach(Ether *e)
1311 {
1312         Ctlr *c;
1313         char name[12];
1314
1315         dprint("m10gattach\n");
1316
1317         qlock(e->ctlr);
1318         c = e->ctlr;
1319         if(c->state != Detached){
1320                 qunlock(c);
1321                 return;
1322         }
1323         if(waserror()){
1324                 c->state = Detached;
1325                 qunlock(c);
1326                 nexterror();
1327         }
1328         reset(e, c);
1329         c->state = Attached;
1330         open0(e, c);
1331         if(c->kprocs == 0){
1332                 c->kprocs++;
1333                 snprint(name, sizeof name, "#l%drxproc", e->ctlrno);
1334                 kproc(name, m10rx, e);
1335                 snprint(name, sizeof name, "#l%dtxproc", e->ctlrno);
1336                 kproc(name, txproc, e);
1337         }
1338         c->state = Runed;
1339         qunlock(c);
1340         poperror();
1341 }
1342
1343 static int
1344 m10gdetach(Ctlr *c)
1345 {
1346         dprint("m10gdetach\n");
1347 //      reset(e->ctlr);
1348         vunmap(c->ram, c->pcidev->mem[0].size);
1349         ctlrfree(c);
1350         return -1;
1351 }
1352
1353 static int
1354 lstcount(Block *b)
1355 {
1356         int i;
1357
1358         i = 0;
1359         for(; b; b = b->next)
1360                 i++;
1361         return i;
1362 }
1363
1364 static long
1365 m10gifstat(Ether *e, void *v, long n, ulong off)
1366 {
1367         char *p;
1368         Ctlr *c;
1369         Stats s;
1370
1371         c = e->ctlr;
1372         p = smalloc(READSTR);
1373         /* no point in locking this because this is done via dma. */
1374         memmove(&s, c->stats, sizeof s);
1375         snprint(p, READSTR,
1376                 "txcnt = %lud\n"  "linkstat = %lud\n"   "dlink = %lud\n"
1377                 "derror = %lud\n" "drunt = %lud\n"      "doverrun = %lud\n"
1378                 "dnosm = %lud\n"  "dnobg = %lud\n"      "nrdma = %lud\n"
1379                 "txstopped = %ud\n" "down = %ud\n"      "updated = %ud\n"
1380                 "valid = %ud\n\n"
1381                 "tx pkt = %lud\n"  "tx bytes = %lld\n"
1382                 "tx cnt = %ud\n"  "tx n = %ud\n"        "tx i = %ud\n"
1383                 "sm cnt = %ud\n"  "sm i = %ud\n"        "sm n = %ud\n"
1384                 "sm lst = %ud\n"
1385                 "bg cnt = %ud\n"  "bg i = %ud\n"        "bg n = %ud\n"
1386                 "bg lst = %ud\n"
1387                 "segsz = %lud\n"   "coal = %lud\n",
1388                 gbit32(s.txcnt),  gbit32(s.linkstat),   gbit32(s.dlink),
1389                 gbit32(s.derror), gbit32(s.drunt),      gbit32(s.doverrun),
1390                 gbit32(s.dnosm),  gbit32(s.dnobg),      gbit32(s.nrdma),
1391                 s.txstopped,  s.down, s.updated, s.valid,
1392                 c->tx.npkt, c->tx.nbytes,
1393                 c->tx.cnt, c->tx.n, c->tx.i,
1394                 c->sm.cnt, c->sm.i, c->sm.pool->n, lstcount(c->sm.pool->head),
1395                 c->bg.cnt, c->bg.i, c->bg.pool->n, lstcount(c->bg.pool->head),
1396                 c->tx.segsz, gbit32((uchar*)c->coal));
1397
1398         n = readstr(off, v, n, p);
1399         free(p);
1400         return n;
1401 }
1402
1403 //static void
1404 //summary(Ether *e)
1405 //{
1406 //      char *buf;
1407 //      int n, i, j;
1408 //
1409 //      if(e == 0)
1410 //              return;
1411 //      buf = malloc(n=250);
1412 //      if(buf == 0)
1413 //              return;
1414 //
1415 //      snprint(buf, n, "oq\n");
1416 //      qsummary(e->oq, buf+3, n-3-1);
1417 //      iprint("%s", buf);
1418 //
1419 //      if(e->f) for(i = 0; e->f[i]; i++){
1420 //              j = snprint(buf, n, "f%d %d\n", i, e->f[i]->type);
1421 //              qsummary(e->f[i]->in, buf+j, n-j-1);
1422 //              print("%s", buf);
1423 //      }
1424 //
1425 //      free(buf);
1426 //}
1427
1428 static void
1429 rxring(Ctlr *c)
1430 {
1431         Done *d;
1432         Slot *s;
1433         Slotparts *sp;
1434         int i;
1435
1436         d = &c->done;
1437         s = d->entry;
1438         for(i = 0; i < d->n; i++) {
1439                 sp = (Slotparts *)(s + i);
1440                 if(sp->len)
1441                         iprint("s[%d] = %d\n", i, sp->len);
1442         }
1443 }
1444
1445 enum {
1446         CMdebug,
1447         CMcoal,
1448         CMwakeup,
1449         CMtxwakeup,
1450         CMqsummary,
1451         CMrxring,
1452 };
1453
1454 static Cmdtab ctab[] = {
1455         CMdebug,        "debug",        2,
1456         CMcoal,         "coal",         2,
1457         CMwakeup,       "wakeup",       1,
1458         CMtxwakeup,     "txwakeup",     1,
1459 //      CMqsummary,     "q",            1,
1460         CMrxring,       "rxring",       1,
1461 };
1462
1463 static long
1464 m10gctl(Ether *e, void *v, long n)
1465 {
1466         int i;
1467         Cmdbuf *c;
1468         Cmdtab *t;
1469
1470         dprint("m10gctl\n");
1471         if(e->ctlr == nil)
1472                 error(Enonexist);
1473
1474         c = parsecmd(v, n);
1475         if(waserror()){
1476                 free(c);
1477                 nexterror();
1478         }
1479         t = lookupcmd(c, ctab, nelem(ctab));
1480         switch(t->index){
1481         case CMdebug:
1482                 debug = (strcmp(c->f[1], "on") == 0);
1483                 break;
1484         case CMcoal:
1485                 i = atoi(c->f[1]);
1486                 if(i < 0 || i > 1000)
1487                         error(Ebadarg);
1488                 *((Ctlr*)e->ctlr)->coal = pbit32(i);
1489                 break;
1490         case CMwakeup:
1491                 wakeup(&((Ctlr*)e->ctlr)->rxrendez); /* you're kidding, right? */
1492                 break;
1493         case CMtxwakeup:
1494                 wakeup(&((Ctlr*)e->ctlr)->txrendez); /* you're kidding, right? */
1495                 break;
1496 //      case CMqsummary:
1497 //              summary(e);
1498 //              break;
1499         case CMrxring:
1500                 rxring(e->ctlr);
1501                 break;
1502         default:
1503                 error(Ebadarg);
1504         }
1505         free(c);
1506         poperror();
1507         return n;
1508 }
1509
1510 static void
1511 m10gshutdown(Ether *e)
1512 {
1513         dprint("m10gshutdown\n");
1514         m10gdetach(e->ctlr);
1515 }
1516
1517 static void
1518 m10gpromiscuous(void *v, int on)
1519 {
1520         Ether *e;
1521         int i;
1522
1523         dprint("m10gpromiscuous\n");
1524         e = v;
1525         if(on)
1526                 i = Cpromisc;
1527         else
1528                 i = Cnopromisc;
1529         cmd(e->ctlr, i, 0);
1530 }
1531
1532 static int      mcctab[]  = { CSleavemc, CSjoinmc };
1533 static char     *mcntab[] = { "leave", "join" };
1534
1535 static void
1536 m10gmulticast(void *v, uchar *ea, int on)
1537 {
1538         Ether *e;
1539         int i;
1540
1541         dprint("m10gmulticast\n");
1542         e = v;
1543         if((i = maccmd(e->ctlr, mcctab[on], ea)) != 0)
1544                 print("m10g: can't %s %E: %d\n", mcntab[on], ea, i);
1545 }
1546
1547 static void
1548 m10gpci(void)
1549 {
1550         Pcidev *p;
1551         Ctlr *t, *c;
1552
1553         t = 0;
1554         for(p = 0; p = pcimatch(p, Vmyricom, 0); ){
1555                 switch(p->did){
1556                 case 0x8:               /* 8a */
1557                         break;
1558                 case 0x9:               /* 8a with msi-x fw */
1559                 case 0xa:               /* 8b */
1560                 case 0xb:               /* 8b2 */
1561                 case 0xc:               /* 2-8b2 */
1562                         /* untested */
1563                         break;
1564                 default:
1565                         print("etherm10g: unknown myricom did %#ux\n", p->did);
1566                         continue;
1567                 }
1568                 c = malloc(sizeof *c);
1569                 if(c == nil){
1570                         print("etherm10g: can't allocate memory\n");
1571                         continue;
1572                 }
1573                 c->pcidev = p;
1574                 pcienable(p);
1575                 c->id = p->did<<16 | p->vid;
1576                 c->boot = pcicap(p, PciCapVND);
1577 //              kickthebaby(p, c);
1578                 pcisetbme(p);
1579                 if(setmem(p, c) == -1){
1580                         print("m10g: setmem failed\n");
1581                         free(c);
1582                         /* cleanup */
1583                         continue;
1584                 }
1585                 if(t)
1586                         t->next = c;
1587                 else
1588                         ctlrs = c;
1589                 t = c;
1590         }
1591 }
1592
1593 static int
1594 m10gpnp(Ether *e)
1595 {
1596         Ctlr *c;
1597
1598         if(ctlrs == nil)
1599                 m10gpci();
1600
1601         for(c = ctlrs; c != nil; c = c->next)
1602                 if(c->active)
1603                         continue;
1604                 else if(e->port == 0 || e->port == c->port)
1605                         break;
1606         if(c == nil)
1607                 return -1;
1608         c->active = 1;
1609
1610         e->ctlr = c;
1611         e->port = c->port;
1612         e->irq = c->pcidev->intl;
1613         e->tbdf = c->pcidev->tbdf;
1614         e->mbps = 10000;
1615         memmove(e->ea, c->ra, Eaddrlen);
1616
1617         e->attach = m10gattach;
1618         e->transmit = m10gtransmit;
1619         e->interrupt = m10ginterrupt;
1620         e->ifstat = m10gifstat;
1621         e->ctl = m10gctl;
1622 //      e->power = m10gpower;
1623         e->shutdown = m10gshutdown;
1624
1625         e->arg = e;
1626         e->promiscuous = m10gpromiscuous;
1627         e->multicast = m10gmulticast;
1628
1629         return 0;
1630 }
1631
1632 void
1633 etherm10glink(void)
1634 {
1635         addethercard("m10g", m10gpnp);
1636 }