]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherm10g.c
pc, pc64: more conservative pcirouting
[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
18 #include "../pc/etherif.h"
19
20 #ifndef KiB
21 #define KiB             1024u                   /* Kibi 0x0000000000000400 */
22 #define MiB             1048576u                /* Mebi 0x0000000000100000 */
23 #endif /* KiB */
24
25 #define dprint(...)     if(debug) print(__VA_ARGS__)
26 #define pcicapdbg(...)
27 #define malign(n)       mallocalign((n), 4*KiB, 0, 0)
28
29 #include "etherm10g2k.i"
30 #include "etherm10g4k.i"
31
32 static int      debug           = 0;
33 static char     Etimeout[]      = "timeout";
34
35 enum {
36         Epromsz = 256,
37         Maxslots= 1024,
38         Align   = 4096,
39         Maxmtu  = 9000,
40         Noconf  = 0xffffffff,
41
42         Fwoffset= 1*MiB,
43         Cmdoff  = 0xf80000,     /* command port offset */
44         Fwsubmt = 0xfc0000,     /* firmware submission command port offset */
45         Rdmaoff = 0xfc01c0,     /* rdma command port offset */
46 };
47
48 enum {
49         CZero,
50         Creset,
51         Cversion,
52
53         CSintrqdma,     /* issue these before Cetherup */
54         CSbigsz,        /* in bytes bigsize = 2^n */
55         CSsmallsz,
56
57         CGsendoff,
58         CGsmallrxoff,
59         CGbigrxoff,
60         CGirqackoff,
61         CGirqdeassoff,
62         CGsendrgsz,
63         CGrxrgsz,
64
65         CSintrqsz,      /* 2^n */
66         Cetherup,       /* above parameters + mtu/mac addr must be set first. */
67         Cetherdn,
68
69         CSmtu,          /* below may be issued live */
70         CGcoaloff,      /* in µs */
71         CSstatsrate,    /* in µs */
72         CSstatsdma,
73
74         Cpromisc,
75         Cnopromisc,
76         CSmac,
77
78         Cenablefc,
79         Cdisablefc,
80
81         Cdmatest,       /* address in d[0-1], d[2]=length */
82
83         Cenableallmc,
84         Cdisableallmc,
85
86         CSjoinmc,
87         CSleavemc,
88         Cleaveallmc,
89
90         CSstatsdma2,    /* adds (unused) multicast stats */
91 };
92
93 typedef union {
94         uint    i[2];
95         uchar   c[8];
96 } Cmd;
97
98 typedef ulong Slot;
99 typedef struct {
100         ushort  cksum;
101         ushort  len;
102 } Slotparts;
103
104 enum {
105         SFsmall = 1,
106         SFfirst = 2,
107         SFalign = 4,
108         SFnotso = 16,
109 };
110
111 typedef struct {
112         ulong   high;
113         ulong   low;
114         ushort  hdroff;
115         ushort  len;
116         uchar   pad;
117         uchar   nrdma;
118         uchar   chkoff;
119         uchar   flags;
120 } Send;
121
122 typedef struct {
123         QLock;
124         Send    *lanai;         /* tx ring (cksum+len in lanai memory) */
125         Send    *host;          /* tx ring (data in our memory) */
126         Block   **bring;
127 //      uchar   *wcfifo;        /* what the heck is a w/c fifo? */
128         int     size;           /* of buffers in the z8's memory */
129         ulong   segsz;
130         uint    n;              /* rxslots */
131         uint    m;              /* mask; rxslots must be a power of two */
132         uint    i;              /* number of segments (not frames) queued */
133         uint    cnt;            /* number of segments sent by the card */
134
135         ulong   npkt;
136         vlong   nbytes;
137 } Tx;
138
139 typedef struct {
140         Lock;
141         Block   *head;
142         uint    size;           /* buffer size of each block */
143         uint    n;              /* n free buffers */
144         uint    cnt;
145 } Bpool;
146
147 static Bpool    smpool  = { .size = 128, };
148 static Bpool    bgpool  = { .size = Maxmtu, };
149
150 typedef struct {
151         Bpool   *pool;          /* free buffers */
152         ulong   *lanai;         /* rx ring; we have no permanent host shadow */
153         Block   **host;         /* called "info" in myricom driver */
154 //      uchar   *wcfifo;        /* cmd submission fifo */
155         uint    m;
156         uint    n;              /* rxslots */
157         uint    i;
158         uint    cnt;            /* number of buffers allocated (lifetime) */
159         uint    allocfail;
160 } Rx;
161
162 /* dma mapped.  unix network byte order. */
163 typedef struct {
164         uchar   txcnt[4];
165         uchar   linkstat[4];
166         uchar   dlink[4];
167         uchar   derror[4];
168         uchar   drunt[4];
169         uchar   doverrun[4];
170         uchar   dnosm[4];
171         uchar   dnobg[4];
172         uchar   nrdma[4];
173         uchar   txstopped;
174         uchar   down;
175         uchar   updated;
176         uchar   valid;
177 } Stats;
178
179 enum {
180         Detached,
181         Attached,
182         Runed,
183 };
184
185 typedef struct {
186         Slot    *entry;
187         uvlong  busaddr;
188         uint    m;
189         uint    n;
190         uint    i;
191 } Done;
192
193 typedef struct Ctlr Ctlr;
194 typedef struct Ctlr {
195         QLock;
196         int     state;
197         int     kprocs;
198         uvlong  port;
199         Pcidev* pcidev;
200         Ctlr*   next;
201         int     active;
202         int     id;             /* do we need this? */
203
204         uchar   ra[Eaddrlen];
205
206         int     ramsz;
207         uchar   *ram;
208
209         ulong   *irqack;
210         ulong   *irqdeass;
211         ulong   *coal;
212
213         char    eprom[Epromsz];
214         ulong   serial;         /* unit serial number */
215
216         QLock   cmdl;
217         Cmd     *cmd;           /* address of command return */
218         uvlong  cprt;           /* bus address of command */
219
220         uvlong  boot;           /* boot address */
221
222         Done    done;
223         Tx      tx;
224         Rx      sm;
225         Rx      bg;
226         Stats   *stats;
227         uvlong  statsprt;
228
229         Rendez  rxrendez;
230         Rendez  txrendez;
231
232         int     msi;
233         ulong   linkstat;
234         ulong   nrdma;
235 } Ctlr;
236
237 static Ctlr     *ctlrs;
238
239 enum {
240         PciCapPMG        = 0x01,        /* power management */
241         PciCapAGP        = 0x02,
242         PciCapVPD        = 0x03,        /* vital product data */
243         PciCapSID        = 0x04,        /* slot id */
244         PciCapMSI        = 0x05,
245         PciCapCHS        = 0x06,        /* compact pci hot swap */
246         PciCapPCIX       = 0x07,
247         PciCapHTC        = 0x08,        /* hypertransport irq conf */
248         PciCapVND        = 0x09,        /* vendor specific information */
249         PciCapHSW        = 0x0C,        /* hot swap */
250         PciCapPCIe       = 0x10,
251         PciCapMSIX       = 0x11,
252 };
253
254 enum {
255         PcieAERC = 1,
256         PcieVC,
257         PcieSNC,
258         PciePBC,
259 };
260
261 enum {
262         AercCCR = 0x18,         /* control register */
263 };
264
265 enum {
266         PcieCTL = 8,
267         PcieLCR = 12,
268         PcieMRD = 0x7000,       /* maximum read size */
269 };
270
271 static int
272 pcicap(Pcidev *p, int cap)
273 {
274         int i, c, off;
275
276         pcicapdbg("pcicap: %x:%d\n", p->vid, p->did);
277         off = 0x34;                     /* 0x14 for cardbus */
278         for(i = 48; i--; ){
279                 pcicapdbg("\t" "loop %x\n", off);
280                 off = pcicfgr8(p, off);
281                 pcicapdbg("\t" "pcicfgr8 %x\n", off);
282                 if(off < 0x40)
283                         break;
284                 off &= ~3;
285                 c = pcicfgr8(p, off);
286                 pcicapdbg("\t" "pcicfgr8 %x\n", c);
287                 if(c == 0xff)
288                         break;
289                 if(c == cap)
290                         return off;
291                 off++;
292         }
293         return 0;
294 }
295
296 /*
297  * this function doesn't work because pcicgr32 doesn't have access
298  * to the pcie extended configuration space.
299  */
300 static int
301 pciecap(Pcidev *p, int cap)
302 {
303         uint off, i;
304
305         off = 0x100;
306         while(((i = pcicfgr32(p, off)) & 0xffff) != cap){
307                 off = i >> 20;
308                 print("m10g: pciecap offset = %ud",  off);
309                 if(off < 0x100 || off >= 4*KiB - 1)
310                         return 0;
311         }
312         print("m10g: pciecap found = %ud",  off);
313         return off;
314 }
315
316 static int
317 setpcie(Pcidev *p)
318 {
319         int off;
320
321         /* set 4k writes */
322         off = pcicap(p, PciCapPCIe);
323         if(off < 64)
324                 return -1;
325         off += PcieCTL;
326         pcicfgw16(p, off, (pcicfgr16(p, off) & ~PcieMRD) | 5<<12);
327         return 0;
328 }
329
330 static int
331 whichfw(Pcidev *p)
332 {
333         char *s;
334         int i, off, lanes, ecrc;
335         ulong cap;
336
337         /* check the number of configured lanes. */
338         off = pcicap(p, PciCapPCIe);
339         if(off < 64)
340                 return -1;
341         off += PcieLCR;
342         cap = pcicfgr16(p, off);
343         lanes = (cap>>4) & 0x3f;
344
345         /* check AERC register.  we need it on.  */
346         off = pciecap(p, PcieAERC);
347         print("; offset %d returned\n", off);
348         cap = 0;
349         if(off != 0){
350                 off += AercCCR;
351                 cap = pcicfgr32(p, off);
352                 print("m10g: %lud cap\n", cap);
353         }
354         ecrc = (cap>>4) & 0xf;
355         /* if we don't like the aerc, kick it here. */
356
357         print("m10g: %d lanes; ecrc=%d; ", lanes, ecrc);
358         if(s = getconf("myriforce")){
359                 i = atoi(s);
360                 if(i != 4*KiB || i != 2*KiB)
361                         i = 2*KiB;
362                 print("fw = %d [forced]\n", i);
363                 return i;
364         }
365         if(lanes <= 4)
366                 print("fw = 4096 [lanes]\n");
367         else if(ecrc & 10)
368                 print("fw = 4096 [ecrc set]\n");
369         else
370                 print("fw = 4096 [default]\n");
371         return 4*KiB;
372 }
373
374 static int
375 parseeprom(Ctlr *c)
376 {
377         int i, j, k, l, bits;
378         char *s;
379
380         dprint("m10g eprom:\n");
381         s = c->eprom;
382         bits = 3;
383         for(i = 0; s[i] && i < Epromsz; i++){
384                 l = strlen(s+i);
385                 dprint("\t%s\n", s+i);
386                 if(strncmp(s+i, "MAC=", 4) == 0 && l == 4+12+5){
387                         bits ^= 1;
388                         j = i + 4;
389                         for(k = 0; k < 6; k++)
390                                 c->ra[k] = strtoul(s+j+3*k, 0, 16);
391                 }else if(strncmp(s+i, "SN=", 3) == 0){
392                         bits ^= 2;
393                         c->serial = atoi(s+i+3);
394                 }
395                 i += l;
396         }
397         if(bits)
398                 return -1;
399         return 0;
400 }
401
402 static ushort
403 pbit16(ushort i)
404 {
405         ushort j;
406         uchar *p;
407
408         p = (uchar*)&j;
409         p[1] = i;
410         p[0] = i>>8;
411         return j;
412 }
413
414 static ushort
415 gbit16(uchar i[2])
416 {
417         ushort j;
418
419         j  = i[1];
420         j |= i[0]<<8;
421         return j;
422 }
423
424 static ulong
425 pbit32(ulong i)
426 {
427         ulong j;
428         uchar *p;
429
430         p = (uchar*)&j;
431         p[3] = i;
432         p[2] = i>>8;
433         p[1] = i>>16;
434         p[0] = i>>24;
435         return j;
436 }
437
438 static ulong
439 gbit32(uchar i[4])
440 {
441         ulong j;
442
443         j  = i[3];
444         j |= i[2]<<8;
445         j |= i[1]<<16;
446         j |= i[0]<<24;
447         return j;
448 }
449
450 static void
451 prepcmd(ulong *cmd, int i)
452 {
453         while(i-- > 0)
454                 cmd[i] = pbit32(cmd[i]);
455 }
456
457 /*
458  * the command looks like this (int 32bit integers)
459  * cmd type
460  * addr (low)
461  * addr (high)
462  * pad (used for dma testing)
463  * response (high)
464  * response (low)
465  * 40 byte = 5 int pad.
466  */
467
468 ulong
469 cmd(Ctlr *c, int type, uvlong data)
470 {
471         ulong buf[16], i;
472         Cmd *cmd;
473
474         qlock(&c->cmdl);
475         cmd = c->cmd;
476         cmd->i[1] = Noconf;
477         memset(buf, 0, sizeof buf);
478         buf[0] = type;
479         buf[1] = data;
480         buf[2] = data >> 32;
481         buf[4] = c->cprt >> 32;
482         buf[5] = c->cprt;
483         prepcmd(buf, 6);
484         coherence();
485         memmove(c->ram + Cmdoff, buf, sizeof buf);
486
487         if(waserror())
488                 nexterror();
489         for(i = 0; i < 15; i++){
490                 if(cmd->i[1] != Noconf){
491                         poperror();
492                         i = gbit32(cmd->c);
493                         qunlock(&c->cmdl);
494                         if(cmd->i[1] != 0)
495                                 dprint("[%lux]", i);
496                         return i;
497                 }
498                 tsleep(&up->sleep, return0, 0, 1);
499         }
500         qunlock(&c->cmdl);
501         iprint("m10g: cmd timeout [%ux %ux] cmd=%d\n",
502                 cmd->i[0], cmd->i[1], type);
503         error(Etimeout);
504         return ~0;                      /* silence! */
505 }
506
507 ulong
508 maccmd(Ctlr *c, int type, uchar *m)
509 {
510         ulong buf[16], i;
511         Cmd *cmd;
512
513         qlock(&c->cmdl);
514         cmd = c->cmd;
515         cmd->i[1] = Noconf;
516         memset(buf, 0, sizeof buf);
517         buf[0] = type;
518         buf[1] = m[0]<<24 | m[1]<<16 | m[2]<<8 | m[3];
519         buf[2] = m[4]<< 8 | m[5];
520         buf[4] = c->cprt >> 32;
521         buf[5] = c->cprt;
522         prepcmd(buf, 6);
523         coherence();
524         memmove(c->ram + Cmdoff, buf, sizeof buf);
525
526         if(waserror())
527                 nexterror();
528         for(i = 0; i < 15; i++){
529                 if(cmd->i[1] != Noconf){
530                         poperror();
531                         i = gbit32(cmd->c);
532                         qunlock(&c->cmdl);
533                         if(cmd->i[1] != 0)
534                                 dprint("[%lux]", i);
535                         return i;
536                 }
537                 tsleep(&up->sleep, return0, 0, 1);
538         }
539         qunlock(&c->cmdl);
540         iprint("m10g: maccmd timeout [%ux %ux] cmd=%d\n",
541                 cmd->i[0], cmd->i[1], type);
542         error(Etimeout);
543         return ~0;                      /* silence! */
544 }
545
546 /* remove this garbage after testing */
547 enum {
548         DMAread = 0x10000,
549         DMAwrite= 0x1,
550 };
551
552 ulong
553 dmatestcmd(Ctlr *c, int type, uvlong addr, int len)
554 {
555         ulong buf[16], i;
556
557         memset(buf, 0, sizeof buf);
558         memset(c->cmd, Noconf, sizeof *c->cmd);
559         buf[0] = Cdmatest;
560         buf[1] = addr;
561         buf[2] = addr >> 32;
562         buf[3] = len * type;
563         buf[4] = c->cprt >> 32;
564         buf[5] = c->cprt;
565         prepcmd(buf, 6);
566         coherence();
567         memmove(c->ram + Cmdoff, buf, sizeof buf);
568
569         if(waserror())
570                 nexterror();
571         for(i = 0; i < 15; i++){
572                 if(c->cmd->i[1] != Noconf){
573                         i = gbit32(c->cmd->c);
574                         if(i == 0)
575                                 error(Eio);
576                         poperror();
577                         return i;
578                 }
579                 tsleep(&up->sleep, return0, 0, 5);
580         }
581         error(Etimeout);
582         return ~0;                      /* silence! */
583 }
584
585 ulong
586 rdmacmd(Ctlr *c, int on)
587 {
588         ulong buf[16], i;
589
590         memset(buf, 0, sizeof buf);
591         c->cmd->i[0] = 0;
592         coherence();
593         buf[0] = c->cprt >> 32;
594         buf[1] = c->cprt;
595         buf[2] = Noconf;
596         buf[3] = c->cprt >> 32;
597         buf[4] = c->cprt;
598         buf[5] = on;
599         prepcmd(buf, 6);
600         memmove(c->ram + Rdmaoff, buf, sizeof buf);
601
602         if(waserror())
603                 nexterror();
604         for(i = 0; i < 20; i++){
605                 if(c->cmd->i[0] == Noconf){
606                         poperror();
607                         return gbit32(c->cmd->c);
608                 }
609                 tsleep(&up->sleep, return0, 0, 1);
610         }
611         error(Etimeout);
612         iprint("m10g: rdmacmd timeout\n");
613         return ~0;                      /* silence! */
614 }
615
616 static int
617 loadfw(Ctlr *c, int *align)
618 {
619         ulong *f, *s, sz;
620         int i;
621
622         if((*align = whichfw(c->pcidev)) == 4*KiB){
623                 f = (ulong*)fw4k;
624                 sz = sizeof fw4k;
625         }else{
626                 f = (ulong*)fw2k;
627                 sz = sizeof fw2k;
628         }
629
630         s = (ulong*)(c->ram + Fwoffset);
631         for(i = 0; i < sz / 4; i++)
632                 s[i] = f[i];
633         return sz & ~3;
634 }
635
636 static int
637 bootfw(Ctlr *c)
638 {
639         int i, sz, align;
640         ulong buf[16];
641         Cmd* cmd;
642
643         if((sz = loadfw(c, &align)) == 0)
644                 return 0;
645         dprint("bootfw %d bytes ... ", sz);
646         cmd = c->cmd;
647
648         memset(buf, 0, sizeof buf);
649         c->cmd->i[0] = 0;
650         coherence();
651         buf[0] = c->cprt >> 32; /* upper dma target address */
652         buf[1] = c->cprt;       /* lower */
653         buf[2] = Noconf;        /* writeback */
654         buf[3] = Fwoffset + 8,
655         buf[4] = sz - 8;
656         buf[5] = 8;
657         buf[6] = 0;
658         prepcmd(buf, 7);
659         coherence();
660         memmove(c->ram + Fwsubmt, buf, sizeof buf);
661
662         for(i = 0; i < 20; i++){
663                 if(cmd->i[0] == Noconf)
664                         break;
665                 delay(1);
666         }
667         dprint("[%lux %lux]", gbit32(cmd->c), gbit32(cmd->c+4));
668         if(i == 20){
669                 print("m10g: cannot load fw\n");
670                 return -1;
671         }
672         dprint("\n");
673         c->tx.segsz = align;
674         return 0;
675 }
676
677 static int
678 kickthebaby(Pcidev *p, Ctlr *c)
679 {
680         /* don't kick the baby! */
681         ulong code;
682
683         pcicfgw8(p,  0x10 + c->boot, 0x3);
684         pcicfgw32(p, 0x18 + c->boot, 0xfffffff0);
685         code = pcicfgr32(p, 0x14 + c->boot);
686
687         dprint("reboot status = %lux\n", code);
688         if(code != 0xfffffff0)
689                 return -1;
690         return 0;
691 }
692
693 typedef struct {
694         uchar   len[4];
695         uchar   type[4];
696         char    version[128];
697         uchar   globals[4];
698         uchar   ramsz[4];
699         uchar   specs[4];
700         uchar   specssz[4];
701 } Fwhdr;
702
703 enum {
704         Tmx     = 0x4d582020,
705         Tpcie   = 0x70636965,
706         Teth    = 0x45544820,
707         Tmcp0   = 0x4d435030,
708 };
709
710 static char *
711 fwtype(ulong type)
712 {
713         switch(type){
714         case Tmx:
715                 return "mx";
716         case Tpcie:
717                 return "PCIe";
718         case Teth:
719                 return "eth";
720         case Tmcp0:
721                 return "mcp0";
722         }
723         return "*GOK*";
724 }
725
726 static int
727 chkfw(Ctlr *c)
728 {
729         ulong off, type;
730         Fwhdr *h;
731
732         off = gbit32(c->ram+0x3c);
733         dprint("firmware %lux\n", off);
734         if((off&3) || off + sizeof *h > c->ramsz){
735                 print("!m10g: bad firmware %lux\n", off);
736                 return -1;
737         }
738         h = (Fwhdr*)(c->ram + off);
739         type = gbit32(h->type);
740         dprint("\t" "type       %s\n", fwtype(type));
741         dprint("\t" "vers       %s\n", h->version);
742         dprint("\t" "ramsz      %lux\n", gbit32(h->ramsz));
743         if(type != Teth){
744                 print("!m10g: bad card type %s\n", fwtype(type));
745                 return -1;
746         }
747
748         return bootfw(c) || rdmacmd(c, 0);
749 }
750
751 static int
752 reset(Ether *e, Ctlr *c)
753 {
754         ulong i, sz;
755
756         if(waserror()){
757                 print("m10g: reset error\n");
758                 nexterror();
759                 return -1;
760         }
761
762         chkfw(c);
763         cmd(c, Creset, 0);
764
765         cmd(c, CSintrqsz, c->done.n * sizeof *c->done.entry);
766         cmd(c, CSintrqdma, c->done.busaddr);
767         c->irqack =   (ulong*)(c->ram + cmd(c, CGirqackoff, 0));
768         /* required only if we're not doing msi? */
769         c->irqdeass = (ulong*)(c->ram + cmd(c, CGirqdeassoff, 0));
770         /* this is the driver default, why fiddle with this? */
771         c->coal = (ulong*)(c->ram + cmd(c, CGcoaloff, 0));
772         *c->coal = pbit32(25);
773
774         dprint("dma stats:\n");
775         rdmacmd(c, 1);
776         sz = c->tx.segsz;
777         i = dmatestcmd(c, DMAread, c->done.busaddr, sz);
778         print("m10g: read %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff));
779         i = dmatestcmd(c, DMAwrite, c->done.busaddr, sz);
780         print(" write %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff));
781         i = dmatestcmd(c, DMAwrite|DMAread, c->done.busaddr, sz);
782         print(" r/w %lud MB/s\n", ((i>>16)*sz*2*2) / (i&0xffff));
783         memset(c->done.entry, 0, c->done.n * sizeof *c->done.entry);
784
785         maccmd(c, CSmac, c->ra);
786 //      cmd(c, Cnopromisc, 0);
787         cmd(c, Cenablefc, 0);
788         e->maxmtu = Maxmtu;
789         cmd(c, CSmtu, e->maxmtu);
790         dprint("CSmtu %d...\n", e->maxmtu);
791
792         poperror();
793         return 0;
794 }
795
796 static void
797 ctlrfree(Ctlr *c)
798 {
799         /* free up all the Block*s, too */
800         free(c->tx.host);
801         free(c->sm.host);
802         free(c->bg.host);
803         free(c->cmd);
804         free(c->done.entry);
805         free(c->stats);
806         free(c);
807 }
808
809 static int
810 setmem(Pcidev *p, Ctlr *c)
811 {
812         ulong i;
813         uvlong raddr;
814         Done *d;
815         void *mem;
816
817         c->tx.segsz = 2048;
818         c->ramsz = 2*MiB - (2*48*KiB + 32*KiB) - 0x100;
819         if(c->ramsz > p->mem[0].size)
820                 return -1;
821
822         raddr = p->mem[0].bar & ~0x0F;
823         mem = vmap(raddr, p->mem[0].size);
824         if(mem == nil){
825                 print("m10g: can't map %8.8lux\n", p->mem[0].bar);
826                 return -1;
827         }
828         dprint("%llux <- vmap(mem[0].size = %ux)\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, 1);
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                 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->detach = m10gshutdown;
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 }