2 * myricom 10g-pcie-8a 10 Gb ethernet driver
3 * © 2007 erik quanstrom, coraid
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.
10 #include "../port/lib.h"
15 #include "../port/error.h"
16 #include "../port/netif.h"
18 #include "../pc/etherif.h"
21 #define KiB 1024u /* Kibi 0x0000000000000400 */
22 #define MiB 1048576u /* Mebi 0x0000000000100000 */
25 #define dprint(...) if(debug) print(__VA_ARGS__)
26 #define pcicapdbg(...)
27 #define malign(n) mallocalign((n), 4*KiB, 0, 0)
29 #include "etherm10g2k.i"
30 #include "etherm10g4k.i"
33 static char Etimeout[] = "timeout";
43 Cmdoff = 0xf80000, /* command port offset */
44 Fwsubmt = 0xfc0000, /* firmware submission command port offset */
45 Rdmaoff = 0xfc01c0, /* rdma command port offset */
53 CSintrqdma, /* issue these before Cetherup */
54 CSbigsz, /* in bytes bigsize = 2^n */
66 Cetherup, /* above parameters + mtu/mac addr must be set first. */
69 CSmtu, /* below may be issued live */
70 CGcoaloff, /* in µs */
71 CSstatsrate, /* in µs */
81 Cdmatest, /* address in d[0-1], d[2]=length */
90 CSstatsdma2, /* adds (unused) multicast stats */
124 Send *lanai; /* tx ring (cksum+len in lanai memory) */
125 Send *host; /* tx ring (data in our memory) */
127 // uchar *wcfifo; /* what the heck is a w/c fifo? */
128 int size; /* of buffers in the z8's memory */
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 */
142 uint size; /* buffer size of each block */
143 uint n; /* n free buffers */
147 static Bpool smpool = { .size = 128, };
148 static Bpool bgpool = { .size = Maxmtu, };
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 */
156 uint n; /* rxslots */
158 uint cnt; /* number of buffers allocated (lifetime) */
162 /* dma mapped. unix network byte order. */
193 typedef struct Ctlr Ctlr;
194 typedef struct Ctlr {
202 int id; /* do we need this? */
214 ulong serial; /* unit serial number */
217 Cmd *cmd; /* address of command return */
218 uvlong cprt; /* bus address of command */
220 uvlong boot; /* boot address */
240 PciCapPMG = 0x01, /* power management */
242 PciCapVPD = 0x03, /* vital product data */
243 PciCapSID = 0x04, /* slot id */
245 PciCapCHS = 0x06, /* compact pci hot swap */
247 PciCapHTC = 0x08, /* hypertransport irq conf */
248 PciCapVND = 0x09, /* vendor specific information */
249 PciCapHSW = 0x0C, /* hot swap */
262 AercCCR = 0x18, /* control register */
268 PcieMRD = 0x7000, /* maximum read size */
272 pcicap(Pcidev *p, int cap)
276 pcicapdbg("pcicap: %x:%d\n", p->vid, p->did);
277 off = 0x34; /* 0x14 for cardbus */
279 pcicapdbg("\t" "loop %x\n", off);
280 off = pcicfgr8(p, off);
281 pcicapdbg("\t" "pcicfgr8 %x\n", off);
285 c = pcicfgr8(p, off);
286 pcicapdbg("\t" "pcicfgr8 %x\n", c);
297 * this function doesn't work because pcicgr32 doesn't have access
298 * to the pcie extended configuration space.
301 pciecap(Pcidev *p, int cap)
306 while(((i = pcicfgr32(p, off)) & 0xffff) != cap){
308 print("m10g: pciecap offset = %ud", off);
309 if(off < 0x100 || off >= 4*KiB - 1)
312 print("m10g: pciecap found = %ud", off);
322 off = pcicap(p, PciCapPCIe);
326 pcicfgw16(p, off, (pcicfgr16(p, off) & ~PcieMRD) | 5<<12);
334 int i, off, lanes, ecrc;
337 /* check the number of configured lanes. */
338 off = pcicap(p, PciCapPCIe);
342 cap = pcicfgr16(p, off);
343 lanes = (cap>>4) & 0x3f;
345 /* check AERC register. we need it on. */
346 off = pciecap(p, PcieAERC);
347 print("; offset %d returned\n", off);
351 cap = pcicfgr32(p, off);
352 print("m10g: %lud cap\n", cap);
354 ecrc = (cap>>4) & 0xf;
355 /* if we don't like the aerc, kick it here. */
357 print("m10g: %d lanes; ecrc=%d; ", lanes, ecrc);
358 if(s = getconf("myriforce")){
360 if(i != 4*KiB || i != 2*KiB)
362 print("fw = %d [forced]\n", i);
366 print("fw = 4096 [lanes]\n");
368 print("fw = 4096 [ecrc set]\n");
370 print("fw = 4096 [default]\n");
377 int i, j, k, l, bits;
380 dprint("m10g eprom:\n");
383 for(i = 0; s[i] && i < Epromsz; i++){
385 dprint("\t%s\n", s+i);
386 if(strncmp(s+i, "MAC=", 4) == 0 && l == 4+12+5){
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){
393 c->serial = atoi(s+i+3);
451 prepcmd(ulong *cmd, int i)
454 cmd[i] = pbit32(cmd[i]);
458 * the command looks like this (int 32bit integers)
462 * pad (used for dma testing)
465 * 40 byte = 5 int pad.
469 cmd(Ctlr *c, int type, uvlong data)
477 memset(buf, 0, sizeof buf);
481 buf[4] = c->cprt >> 32;
485 memmove(c->ram + Cmdoff, buf, sizeof buf);
489 for(i = 0; i < 15; i++){
490 if(cmd->i[1] != Noconf){
498 tsleep(&up->sleep, return0, 0, 1);
501 iprint("m10g: cmd timeout [%ux %ux] cmd=%d\n",
502 cmd->i[0], cmd->i[1], type);
504 return ~0; /* silence! */
508 maccmd(Ctlr *c, int type, uchar *m)
516 memset(buf, 0, sizeof buf);
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;
524 memmove(c->ram + Cmdoff, buf, sizeof buf);
528 for(i = 0; i < 15; i++){
529 if(cmd->i[1] != Noconf){
537 tsleep(&up->sleep, return0, 0, 1);
540 iprint("m10g: maccmd timeout [%ux %ux] cmd=%d\n",
541 cmd->i[0], cmd->i[1], type);
543 return ~0; /* silence! */
546 /* remove this garbage after testing */
553 dmatestcmd(Ctlr *c, int type, uvlong addr, int len)
557 memset(buf, 0, sizeof buf);
558 memset(c->cmd, Noconf, sizeof *c->cmd);
563 buf[4] = c->cprt >> 32;
567 memmove(c->ram + Cmdoff, buf, sizeof buf);
571 for(i = 0; i < 15; i++){
572 if(c->cmd->i[1] != Noconf){
573 i = gbit32(c->cmd->c);
579 tsleep(&up->sleep, return0, 0, 5);
582 return ~0; /* silence! */
586 rdmacmd(Ctlr *c, int on)
590 memset(buf, 0, sizeof buf);
593 buf[0] = c->cprt >> 32;
596 buf[3] = c->cprt >> 32;
600 memmove(c->ram + Rdmaoff, buf, sizeof buf);
604 for(i = 0; i < 20; i++){
605 if(c->cmd->i[0] == Noconf){
607 return gbit32(c->cmd->c);
609 tsleep(&up->sleep, return0, 0, 1);
612 iprint("m10g: rdmacmd timeout\n");
613 return ~0; /* silence! */
617 loadfw(Ctlr *c, int *align)
622 if((*align = whichfw(c->pcidev)) == 4*KiB){
630 s = (ulong*)(c->ram + Fwoffset);
631 for(i = 0; i < sz / 4; i++)
643 if((sz = loadfw(c, &align)) == 0)
645 dprint("bootfw %d bytes ... ", sz);
648 memset(buf, 0, sizeof buf);
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,
660 memmove(c->ram + Fwsubmt, buf, sizeof buf);
662 for(i = 0; i < 20; i++){
663 if(cmd->i[0] == Noconf)
667 dprint("[%lux %lux]", gbit32(cmd->c), gbit32(cmd->c+4));
669 print("m10g: cannot load fw\n");
678 kickthebaby(Pcidev *p, Ctlr *c)
680 /* don't kick the baby! */
683 pcicfgw8(p, 0x10 + c->boot, 0x3);
684 pcicfgw32(p, 0x18 + c->boot, 0xfffffff0);
685 code = pcicfgr32(p, 0x14 + c->boot);
687 dprint("reboot status = %lux\n", code);
688 if(code != 0xfffffff0)
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);
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));
744 print("!m10g: bad card type %s\n", fwtype(type));
748 return bootfw(c) || rdmacmd(c, 0);
752 reset(Ether *e, Ctlr *c)
757 print("m10g: reset error\n");
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);
774 dprint("dma stats:\n");
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);
785 maccmd(c, CSmac, c->ra);
786 // cmd(c, Cnopromisc, 0);
787 cmd(c, Cenablefc, 0);
789 cmd(c, CSmtu, e->maxmtu);
790 dprint("CSmtu %d...\n", e->maxmtu);
799 /* free up all the Block*s, too */
810 setmem(Pcidev *p, Ctlr *c)
818 c->ramsz = 2*MiB - (2*48*KiB + 32*KiB) - 0x100;
819 if(c->ramsz > p->mem[0].size)
822 raddr = p->mem[0].bar & ~0x0F;
823 mem = vmap(raddr, p->mem[0].size);
825 print("m10g: can't map %8.8lux\n", p->mem[0].bar);
828 dprint("%llux <- vmap(mem[0].size = %ux)\n", raddr, p->mem[0].size);
831 c->cmd = malign(sizeof *c->cmd);
832 c->cprt = PCIWADDR(c->cmd);
837 i = d->n * sizeof *d->entry;
838 d->entry = malign(i);
839 memset(d->entry, 0, i);
840 d->busaddr = PCIWADDR(d->entry);
842 c->stats = malign(sizeof *c->stats);
843 memset(c->stats, 0, sizeof *c->stats);
844 c->statsprt = PCIWADDR(c->stats);
846 memmove(c->eprom, c->ram + c->ramsz - Epromsz, Epromsz-2);
847 return setpcie(p) || parseeprom(c);
851 whichrx(Ctlr *c, int sz)
853 if(sz <= smpool.size)
864 if((bp = rx->pool->head) != nil){
865 rx->pool->head = bp->next;
867 _xinc(&bp->ref); /* prevent bp from being freed */
875 rbfree(Block *b, Bpool *p)
877 b->rp = b->wp = (uchar*)PGROUND((uintptr)b->base);
878 b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
903 ulong buf[16], i, idx, e;
910 memset(buf, 0, sizeof buf);
911 e = (rx->i - rx->cnt) & ~7;
913 while(p->n >= 8 && e){
914 idx = rx->cnt & rx->m;
915 for(i = 0; i < 8; i++){
917 buf[i*2] = pbit32((uvlong)PCIWADDR(b->wp) >> 32);
918 buf[i*2+1] = pbit32(PCIWADDR(b->wp));
922 memmove(rx->lanai + 2*idx, buf, sizeof buf);
928 print("m10g: should panic? pool->n = %d", p->n);
933 * if (c->mtrr >= 0) {
934 * c->tx.wcfifo = c->ram+0x200000;
935 * c->sm.wcfifo = c->ram+0x300000;
936 * c->bg.wcfifo = c->ram+0x340000;
945 for(i = 0; j > (1 << i); i++)
963 open0(Ether *e, Ctlr *c)
968 entries = cmd(c, CGsendrgsz, 0) / sizeof *c->tx.lanai;
969 c->tx.lanai = (Send*)(c->ram + cmd(c, CGsendoff, 0));
970 c->tx.host = emalign(entries * sizeof *c->tx.host);
971 c->tx.bring = emalign(entries * sizeof *c->tx.bring);
975 entries = cmd(c, CGrxrgsz, 0)/8;
976 c->sm.pool = &smpool;
977 cmd(c, CSsmallsz, c->sm.pool->size);
978 c->sm.lanai = (ulong*)(c->ram + cmd(c, CGsmallrxoff, 0));
981 c->sm.host = emalign(entries * sizeof *c->sm.host);
983 c->bg.pool = &bgpool;
984 c->bg.pool->size = nextpow(2 + e->maxmtu); /* 2-byte alignment pad */
985 cmd(c, CSbigsz, c->bg.pool->size);
986 c->bg.lanai = (ulong*)(c->ram + cmd(c, CGbigrxoff, 0));
989 c->bg.host = emalign(entries * sizeof *c->bg.host);
991 sz = c->sm.pool->size + BY2PG;
992 for(i = 0; i < c->sm.n; i++){
993 if((b = allocb(sz)) == 0)
998 sz = c->bg.pool->size + BY2PG;
999 for(i = 0; i < c->bg.n; i++){
1000 if((b = allocb(sz)) == 0)
1006 cmd(c, CSstatsdma, c->statsprt);
1010 cmd(c, Cetherup, 0);
1027 sp = (Slotparts *)(s + i);
1034 l = gbit16((uchar*)&l);
1035 //dprint("nextb: i=%d l=%d\n", d->i, l);
1037 if(rx->i >= rx->cnt){
1038 iprint("m10g: overrun\n");
1045 iprint("m10g: error rx to no block. memory is hosed.\n");
1050 b->flag |= Bipck|Btcpck|Budpck;
1054 b->lim = b->wp; /* lie like a dog. */
1069 sp = (Slotparts *)(s + (d->i & d->m));
1072 c->irqack[0] = pbit32(3);
1088 sleep(&c->rxrendez, rxcansleep, c);
1089 while(b = nextblock(c))
1095 txcleanup(Tx *tx, ulong n)
1105 * if tx->cnt == tx->i, yet tx->npkt == n-1, we just
1106 * caught ourselves and myricom card updating.
1109 j = tx->cnt & tx->m;
1110 if(b = tx->bring[j]){
1112 tx->nbytes += BLEN(b);
1117 if(tx->cnt == tx->i)
1120 iprint("m10g: tx ovrun: %lud %lud\n", n, tx->npkt);
1132 if(c->tx.cnt != c->tx.i && c->tx.npkt != gbit32(c->stats->txcnt))
1148 sleep(&c->txrendez, txcansleep, c);
1149 txcleanup(tx, gbit32(c->stats->txcnt));
1154 submittx(Tx *tx, int n)
1163 for(i = n-1; i >= 0; i--)
1164 memmove(l+(i + i0 & m), h+(i + i0 & m), sizeof *h);
1170 nsegments(Block *b, int segsz)
1172 uintptr bus, end, slen, len;
1175 bus = PCIWADDR(b->rp);
1177 for(len = BLEN(b); len; len -= slen){
1178 end = bus + segsz & ~(segsz-1);
1189 m10gtransmit(Ether *e)
1192 ulong i, cnt, rdma, nseg, count, end, bus, len, segsz;
1196 Send *s, *s0, *s0m8;
1205 s = tx->host + (tx->i & tx->m);
1207 s0 = tx->host + (cnt & tx->m);
1208 s0m8 = tx->host + ((cnt - 8) & tx->m);
1210 for(; s >= s0 || s < s0m8; i += nseg){
1211 if((b = qget(e->oq)) == nil)
1213 flags = SFfirst|SFnotso;
1214 if((len = BLEN(b)) < 1520)
1216 rdma = nseg = nsegments(b, segsz);
1217 bus = PCIWADDR(b->rp);
1218 for(; len; len -= slen){
1219 end = (bus + segsz) & ~(segsz-1);
1223 s->low = pbit32(bus);
1224 s->len = pbit16(slen);
1229 if(++s == tx->host + tx->n)
1235 tx->bring[(i + nseg - 1) & tx->m] = b;
1237 submittx(tx, count);
1240 s0 = tx->host + (cnt & tx->m);
1241 s0m8 = tx->host + ((cnt - 8) & tx->m);
1248 checkstats(Ether *e, Ctlr *c, Stats *s)
1255 i = gbit32(s->linkstat);
1256 if(c->linkstat != i){
1259 dprint("m10g: link up\n");
1261 dprint("m10g: link down\n");
1263 i = gbit32(s->nrdma);
1265 dprint("m10g: rdma timeout %ld\n", i);
1275 for(i = 0; i < 1024*1024; i++){
1276 if(c->stats->valid == 0)
1283 m10ginterrupt(Ureg *, void *v)
1291 if(c->state != Runed || c->stats->valid == 0) /* not ready for us? */
1294 if(c->stats->valid & 1)
1295 wakeup(&c->rxrendez);
1296 if(gbit32(c->stats->txcnt) != c->tx.npkt)
1297 wakeup(&c->txrendez);
1301 c->stats->valid = 0;
1303 checkstats(e, c, c->stats);
1304 c->irqack[1] = pbit32(3);
1308 m10gattach(Ether *e)
1313 dprint("m10gattach\n");
1317 if(c->state != Detached){
1322 c->state = Detached;
1327 c->state = Attached;
1331 snprint(name, sizeof name, "#l%drxproc", e->ctlrno);
1332 kproc(name, m10rx, e);
1333 snprint(name, sizeof name, "#l%dtxproc", e->ctlrno);
1334 kproc(name, txproc, e);
1344 dprint("m10gdetach\n");
1346 vunmap(c->ram, c->pcidev->mem[0].size);
1357 for(; b; b = b->next)
1363 m10gifstat(Ether *e, void *v, long n, ulong off)
1370 p = smalloc(READSTR);
1371 /* no point in locking this because this is done via dma. */
1372 memmove(&s, c->stats, sizeof s);
1374 "txcnt = %lud\n" "linkstat = %lud\n" "dlink = %lud\n"
1375 "derror = %lud\n" "drunt = %lud\n" "doverrun = %lud\n"
1376 "dnosm = %lud\n" "dnobg = %lud\n" "nrdma = %lud\n"
1377 "txstopped = %ud\n" "down = %ud\n" "updated = %ud\n"
1379 "tx pkt = %lud\n" "tx bytes = %lld\n"
1380 "tx cnt = %ud\n" "tx n = %ud\n" "tx i = %ud\n"
1381 "sm cnt = %ud\n" "sm i = %ud\n" "sm n = %ud\n"
1383 "bg cnt = %ud\n" "bg i = %ud\n" "bg n = %ud\n"
1385 "segsz = %lud\n" "coal = %lud\n",
1386 gbit32(s.txcnt), gbit32(s.linkstat), gbit32(s.dlink),
1387 gbit32(s.derror), gbit32(s.drunt), gbit32(s.doverrun),
1388 gbit32(s.dnosm), gbit32(s.dnobg), gbit32(s.nrdma),
1389 s.txstopped, s.down, s.updated, s.valid,
1390 c->tx.npkt, c->tx.nbytes,
1391 c->tx.cnt, c->tx.n, c->tx.i,
1392 c->sm.cnt, c->sm.i, c->sm.pool->n, lstcount(c->sm.pool->head),
1393 c->bg.cnt, c->bg.i, c->bg.pool->n, lstcount(c->bg.pool->head),
1394 c->tx.segsz, gbit32((uchar*)c->coal));
1396 n = readstr(off, v, n, p);
1409 // buf = malloc(n=250);
1413 // snprint(buf, n, "oq\n");
1414 // qsummary(e->oq, buf+3, n-3-1);
1415 // iprint("%s", buf);
1417 // if(e->f) for(i = 0; e->f[i]; i++){
1418 // j = snprint(buf, n, "f%d %d\n", i, e->f[i]->type);
1419 // qsummary(e->f[i]->in, buf+j, n-j-1);
1420 // print("%s", buf);
1436 for(i = 0; i < d->n; i++) {
1437 sp = (Slotparts *)(s + i);
1439 iprint("s[%d] = %d\n", i, sp->len);
1452 static Cmdtab ctab[] = {
1453 CMdebug, "debug", 2,
1455 CMwakeup, "wakeup", 1,
1456 CMtxwakeup, "txwakeup", 1,
1457 // CMqsummary, "q", 1,
1458 CMrxring, "rxring", 1,
1462 m10gctl(Ether *e, void *v, long n)
1468 dprint("m10gctl\n");
1477 t = lookupcmd(c, ctab, nelem(ctab));
1480 debug = (strcmp(c->f[1], "on") == 0);
1484 if(i < 0 || i > 1000)
1486 *((Ctlr*)e->ctlr)->coal = pbit32(i);
1489 wakeup(&((Ctlr*)e->ctlr)->rxrendez); /* you're kidding, right? */
1492 wakeup(&((Ctlr*)e->ctlr)->txrendez); /* you're kidding, right? */
1509 m10gshutdown(Ether *e)
1511 dprint("m10gshutdown\n");
1512 m10gdetach(e->ctlr);
1516 m10gpromiscuous(void *v, int on)
1521 dprint("m10gpromiscuous\n");
1530 static int mcctab[] = { CSleavemc, CSjoinmc };
1531 static char *mcntab[] = { "leave", "join" };
1534 m10gmulticast(void *v, uchar *ea, int on)
1539 dprint("m10gmulticast\n");
1541 if((i = maccmd(e->ctlr, mcctab[on], ea)) != 0)
1542 print("m10g: can't %s %E: %d\n", mcntab[on], ea, i);
1552 for(p = 0; p = pcimatch(p, Vmyricom, 0); ){
1556 case 0x9: /* 8a with msi-x fw */
1559 case 0xc: /* 2-8b2 */
1563 print("etherm10g: unknown myricom did %#ux\n", p->did);
1566 c = malloc(sizeof *c);
1568 print("etherm10g: can't allocate memory\n");
1572 c->id = p->did<<16 | p->vid;
1573 c->boot = pcicap(p, PciCapVND);
1574 // kickthebaby(p, c);
1576 if(setmem(p, c) == -1){
1577 print("m10g: setmem failed\n");
1598 for(c = ctlrs; c != nil; c = c->next)
1601 else if(e->port == 0 || e->port == c->port)
1609 e->irq = c->pcidev->intl;
1610 e->tbdf = c->pcidev->tbdf;
1612 memmove(e->ea, c->ra, Eaddrlen);
1614 e->attach = m10gattach;
1615 e->detach = m10gshutdown;
1616 e->transmit = m10gtransmit;
1617 e->interrupt = m10ginterrupt;
1618 e->ifstat = m10gifstat;
1620 // e->power = m10gpower;
1621 e->shutdown = m10gshutdown;
1624 e->promiscuous = m10gpromiscuous;
1625 e->multicast = m10gmulticast;
1633 addethercard("m10g", m10gpnp);