2 * marvell 88e8057 yukon2
3 * copyright © 2009-10 erik quanstrom
6 #include "../port/lib.h"
11 #include "../port/error.h"
12 #include "../port/netif.h"
15 #define Pciwaddrh(x) 0
16 #define Pciwaddrl(x) PCIWADDR(x)
17 #define is64() (sizeof(uintptr) == 8)
18 #define dprint(...) if(debug) print(__VA_ARGS__); else {}
20 extern void sfence(void);
31 Rringl = Rringcnt - 8,
44 Ctst = 0x0004/2, /* control and status */
45 Pwrctl = 0x0007, /* power control */
46 Isr = 0x0008/4, /* interrupt src */
47 Ism = 0x000c/4, /* interrupt mask */
48 Hwe = 0x0010/4, /* hw error */
49 Hwem = 0x0014/4, /* hw error mask*/
52 Lisr = 0x0028/4, /* leave isr */
53 Macadr = 0x0100, /* mac address 2ports*3 */
57 Ramcnt = 0x011c, /* # of 4k blocks */
65 Rictl = 0x01a0, /* ri ram buffer ctl */
66 Rib = 0x0190, /* ri buffer0 */
68 /* other unoffset registers */
69 Asfcs = 0x0e68, /* asf command and status */
72 Statctl = 0x0e80/4, /* status */
73 Stattl = 0x0e84/2, /* tail (previous) status addr */
74 Stataddr = 0x0e88/4, /* status address low */
77 Statwm = 0x0eac, /* stat watermark */
78 Statiwm = 0x0ead, /* isr stat watermark */
80 Dpolltm = 0x0e08/4, /* descriptor pool timer */
83 Tgv = 0x0e14/4, /* gmac timer current value */
84 Tgc = 0x0e18, /* gmac timer ctl */
85 Tgt = 0x0e1a, /* gmac timer test */
87 Tsti = 0x0ec0/4, /* stat tx timer ini */
88 Tlti = 0x0eb0/4, /* level */
89 Titi = 0x0ed0/4, /* isr */
91 Tstc = 0x0ec8, /* stat tx timer ctl */
92 Tltc = 0x0eb8, /* level timer ctl */
93 Titc = 0x0ed8, /* isr timer ctl */
95 /* “gmac” registers */
102 Serctl = 0x018/2, /* serial mode */
103 Mchash = 0x034/2, /* 4 registers; 4 bytes apart */
105 /* interrupt sources and masks */
108 Trirq = 0x04c/2, /* tx/rx overflow irq source */
113 Smictl = 0x080/2, /* serial mode control */
117 Ea0 = 0x01c/2, /* 3 16 bit gmac registers */
123 Txactl = 0x210, /* transmit arbiter ctl */
125 Grxea = 0x0c40/4, /* rx fifo end address */
126 Gfrxctl = 0x0c48/4, /* gmac rxfifo ctl */
127 Grxfm = 0x0c4c/4, /* fifo flush mask */
128 Grxft = 0x0c50/4, /* fifo flush threshold */
129 Grxtt = 0x0c54/4, /* rx truncation threshold */
130 Gmfea = 0x0d40/4, /* end address */
131 Gmfae = 0x0d44/4, /* almost empty thresh */
132 Gmfctl = 0x0d48/4, /* tx gmac fifo ctl */
134 Rxphi = 0x0c58, /* pause high watermark */
135 Rxplo = 0x0c5c, /* pause low watermark */
142 Mac = 0x0f00/4, /* global mac control */
143 Phy = 0x0f04/4, /* phy control register */
145 Irq = 0x0f08, /* irq source */
146 Irqm = 0x0f0c, /* irq mask */
149 /* queue registers; all offsets from Qbase*/
151 Qportsz = 0x0080, /* BOTCH; tx diff is 2x rx diff */
164 Qcsr = 0x34, /* 32bit */
168 /* buffer registers; all offsets from Rbase */
175 Rpon = 0x10, /* pause frames on */
176 Rpoff = 0x14, /* pause frames off */
177 Rhon = 0x18, /* high-priority frames on */
178 Rhoff = 0x1c, /* high-priority frames off */
184 Plidx = 0x04, /* last addr; 16 bit */
187 Pgetidx = 0x10, /* 16 bit */
188 Pputidx = 0x14, /* 16 bit */
189 Pfifow = 0x20, /* 8 bit */
190 Pfifor = 0x24, /* 8 bit */
191 Pfifowm = 0x20, /* 8 bit */
193 /* indirect phy registers */
198 Phyana = 0x004, /* auto neg advertisement */
199 Phylpa = 0x005, /* link partner ability */
200 Phyanee = 0x006, /* auto neg adv expansion */
201 Phynp = 0x007, /* next page */
202 Phylnp = 0x008, /* link partner next page */
205 Phyphy = 0x010, /* phy specific ctl */
207 Phyintm = 0x012, /* phy interrupt mask */
210 Phyrxe = 0x015, /* rx error counter */
211 Phypage = 0x016, /* external address */
212 Phypadr = 0x01d, /* phy page address */
218 Aspglinkdn = 1<<14, /* gphy link down */
221 Aspmsk = Aspforce | Aspglinkdn | Aspfempty | Aspclkrun,
227 Sfast = 1<<15, /* 100mbit */
229 Txnofc = 1<<13, /* tx flow control disabled */
230 Link = 1<<12, /* link up */
231 Pausest = 1<<11, /* pause state */
235 Physc = 1<<5, /* phy status change */
236 Sgbe = 1<<4, /* gbe speed */
237 Rxnofc = 1<<2, /* rx flow control disabled */
238 Promisc = 1<<1, /* promiscuous mode enabled */
248 Fpass = 1<<6, /* "force link pass" ? */
251 Fasten = 1<<3, /* enable 100mbit */
252 Adudis = 1<<2, /* disable auto upd duplex */
253 Afcdis = 1<<1, /* disable auto upd flow ctl */
254 Aspddis = 1<<0, /* disable auto upd speed */
257 Ufilter = 1<<15, /* unicast filter */
258 Mfilter = 1<<14, /* multicast filter */
259 Rmcrc = 1<<13, /* remove frame crc */
269 /* Asfcs: yukex only */
270 Asfbrrst = 1<<9, /* bridge reset */
271 Asfcpurst = 1<<8, /* cpu reset */
272 Asfucrst = 3<<0, /* µctlr reset */
275 Asfhvos = 1<<4, /* os present */
289 Nomacsec = 1<<13 | 1<<11,
301 Txovfl = 1<<5, /* tx counter overflow */
302 Rxovfl = 1<<4, /* rx counter overflow */
303 Txurun = 1<<3, /* transmit fifo underrun */
304 Txdone = 1<<2, /* frame tx done */
305 Rxorun = 1<<1, /* rx fifo overrun */
306 Rxdone = 1<<0, /* frame rx done */
322 Asfdis = 1<<12, /* asf disable */
323 Clken = 1<<11, /* enable clock */
327 Mstopped = 1<<5, /* master is stopped */
328 Mstop = 1<<4, /* stop master */
329 Mstrclr = 1<<3, /* master reset clear */
330 Mstrrset = 1<<2, /* master reset */
353 /* csr interrupts: Isrc2, Eisr, etc. */
355 Ibmu = 1<<30, /* sring irq */
361 Itxs = 1<<1, /* descriptor error */
362 Itx = 1<<0, /* descriptor error */
366 Ierror = (Imac | Itx | Irx)*(1 | 1<<Iphy2base),
368 /* hwe interrupts: Hwe Hwem */
369 Htsof = 1<<29, /* timer stamp overflow */
371 Hmerr = 1<<27, /* master error */
372 Hstatus = 1<<26, /* status exception */
373 Hpcie = 1<<25, /* pcie error */
374 Hpcie2 = 1<<24, /* " */
376 Hrparity = 1<<5, /* ram read parity error */
377 Hwparity = 1<<4, /* ram write parity error */
378 Hmfault = 1<<3, /* mac fault */
379 Hrxparity = 1<<2, /* rx parity */
380 Htcptxs = 1<<1, /* tcp length mismatch */
381 Htcptxa = 1<<0, /* tcp length mismatch */
386 Hdflt = Htsof | Hmerr | Hstatus | Hmask*(H1base | H2base),
393 Link2inactive = 1<<7,
397 Phy100 = 1<<14, /* manual enable 100mbit */
398 Aneen = 1<<12, /* auto negotiation enable */
399 Phyoff = 1<<11, /* turn phy off */
400 Anerst = 1<<9, /* auto neg reset */
402 Phy1000 = 1<<5, /* manual enable gbe */
405 Annp = 1<<15, /* request next page */
406 Anack = 1<<14, /* ack rx (read only) */
407 Anrf = 1<<13, /* remote fault */
408 Anpa = 1<<11, /* try asymmetric pause */
409 Anp = 1<<10, /* try pause */
415 Anall = An100f | An100h | An10f | An10h | Anonly,
418 Gbef = 1<<9, /* auto neg gbe full */
419 Gbeh = 1<<8, /* auto neg gbe half */
420 Gbexf = 1<<6, /* auto neg gbe full fiber */
421 Gbexh = 1<<5, /* auto neg gbe full fiber */
424 Pptf = 3<<14, /* tx fifo depth */
425 Pprf = 3<<12, /* rx fifo depth */
426 Pped = 3<<8, /* energy detect */
427 Ppmdix = 3<<5, /* mdix conf */
428 Ppmdixa = 3<<5, /* automdix */
430 Ppengy = 1<<14, /* fe+ enable energy detect */
431 Ppscrdis = 1<<9, /* fe+ scrambler disable */
432 Ppnpe = 1<<12, /* fe+ enable next page */
437 Phypr = 1<<12, /* page rx */
438 Phydone = 1<<11, /* speed and duplex neg. done */
442 Pdwnsh = 1<<5, /* downshift */
443 Penergy = 1<<4, /* energy detect */
444 Ptxpause = 1<<3, /* tx pause enabled */
445 Prxpause = 1<<2, /* rx pause enabled */
446 Ppol = 1<<2, /* polarity */
447 Pjarjar = 1<<1, /* mesa no understasa */
450 Anerr = 1<<15, /* an error */
451 Lsp = 1<<14, /* link speed change */
452 Andc = 1<<13, /* an duplex change */
454 Lsc = 1<<10, /* link status change */
455 Symerr = 1<<9, /* symbol error */
456 Fcarr = 1<<8, /* false carrier */
460 Engych = 1<<4, /* energy change */
461 Dtech = 1<<2, /* dte power det status */
462 Polch = 1<<1, /* polarity change */
466 Dnmstr = 1<<9, /* master downshift; 0: 1x; 1: 2x; 2: 3x */
472 Tgclr = 1<<0, /* clear irq */
475 Tstwen = 1<<1, /* enable config reg r/w */
476 Tstwdis = 1<<0, /* disable config reg r/w */
488 Rsfon = 1<<5, /* enable store/fwd */
501 Qsumen = 1<<13, /* tcp/ip cksum */
503 Qcirqpar = 1<<11, /* clear irq on parity errors */
516 Qallclr = Qfiforst | Qfifooff | Qrstclr,
517 Qgo = Qcirqpar | Qcirqck | Qstart | Qfifoen | Qenable,
520 Qckoff = 1<<31, /* tx: auto checksum off */
522 Qramdis = 1<<24, /* rx: ram disable */
525 Prefon = 1<<3, /* prefetch on */
531 Hw = 0x80, /* bitmask */
532 Ock = 0x12, /* tcp checksum start */
537 Orxts = 0x61, /* rx timestamp */
541 Omacs = 0x6c, /* macsec */
551 Gfroon = 1<<19, /* flush on rx overrun */
553 Gffon = 1<<7, /* rx fifo flush mode on */
561 Gmfsfoff = 1<<31, /* disable store-forward (ec ultra) */
562 Gmfsfon = 1<<30, /* able store-forward (ec ultra) */
563 Gmfvon = 1<<25, /* vlan tag on */
564 Gmfvoff = 1<<24, /* vlan off */
565 Gmfjon = 1<<23, /* jumbo on (ec ultra) */
566 Gmfjoff = 1<<22, /* jumbo off */
567 Gmfcfu = 1<<6, /* clear fifio underrun irq */
568 Gmfcfc = 1<<5, /* clear frame complete irq */
569 Gmfcpe = 1<<4, /* clear parity error irq */
580 Fmc = 1<<10, /* multicast */
582 Fok = 1<<8, /* good frame */
586 Ftoobg = 1<<4, /* oversized */
587 Ffrag = 1<<3, /* fragment */
589 Ffifoof = 1<<0, /* fifo overflow */
590 Ferror = Ffifoof | Fcrcerr | Ffrag | Ftoobg
591 | Fmiierr | Fbadfc | Ftoosm | Fjabbr,
593 /* rx checksum bits in Status.ctl */
594 Badck = 5, /* arbitrary bad checksum */
596 Ctcpok = 1<<7, /* tcp or udp cksum ok */
600 /* more status ring rx bits */
602 Rxjab = 1<<12, /* jabber */
603 Rxsmall = 1<<11, /* too small */
604 Rxmc = 1<<10, /* multicast */
605 Rxbc = 1<<9, /* bcast */
607 Rxfcok = 1<<7, /* flow control pkt */
610 Rxbig = 1<<4, /* too big */
613 Rxfov = 1<<0, /* fifo overflow */
614 Rxerror = Rxfov | Rxcrcerr | Rxfrag | Rxbig | Rxmiierr
615 | Rxfcbad | Rxsmall | Rxjab,
625 Fancy =Fgbe | Fnewphy | Fapwr,
635 Yukba, /* doesn't exist */
640 typedef struct Chipid Chipid;
641 typedef struct Ctlr Ctlr;
642 typedef void (*Freefn)(Block*);
643 typedef struct Kproc Kproc;
644 typedef struct Mc Mc;
645 typedef struct Stattab Stattab;
646 typedef struct Status Status;
647 typedef struct Sring Sring;
648 typedef struct Vtab Vtab;
672 Ctlr *oport; /* port 2 */
695 Block *tbring[Tringcnt];
697 Block *rbring[Rringcnt];
727 static Chipid idtab[] = {
728 [Yukxl] Fgbe | Fnewphy, 0xff, 156, "yukon-2 xl",
729 [Yukecu] Fancy, 0xff, 125, "yukon-2 ec ultra",
730 [Yukex] Fancy | Fnewle, 0xff, 125, "yukon-2 extreme",
731 [Yukec] Fgbe, 2, 125, "yukon-2 ec",
732 [Yukfe] 0, 0xff, 100, "yukon-2 fe",
733 [Yukfep] Fnewphy|Fapwr | Fnewle, 0xff, 50, "yukon-2 fe+",
734 [Yuksup] Fgbe | Fnewphy | Fnewle, 0xff, 125, "yukon-2 supreme",
735 [Yukul2] Fgbe |Fapwr, 0xff, 125, "yukon-2 ultra2",
736 [Yukba] 0, 0, 0, "??",
737 [Yukopt] Fancy, 0xff, 125, "yukon-2 optima",
740 static Vtab vtab[] = {
741 0x11ab, 0x4354, 1514, "88e8040", /* unsure on mtu */
742 0x11ab, 0x4362, 1514, "88e8053",
743 0x11ab, 0x4364, 1514, "88e8056",
744 0x11ab, 0x4380, 1514, "88e8057",
745 0x11ab, 0x436b, 1514, "88e8071", /* unsure on mtu */
746 0x1186, 0x4b00, 9000, "dge-560t",
747 0x1186, 0x4b02, 1514, "dge-550sx",
748 0x1186, 0x4b03, 1514, "dge-550t",
751 static Stattab stattab[] = {
763 80, "rx frames < 64",
764 88, "rx frames < 64 fcs",
766 104, "rx frames 65-127",
767 112, "rx frames 128-255",
768 120, "rx frames 256-511",
769 128, "rx frames 512-1023",
770 136, "rx frames 1024-1518",
771 144, "rx frames 1519-mtu",
772 152, "rx frames too long",
774 176, "rx fifo oflow",
785 248, "tx frames 65-127",
786 256, "tx frames 128-255",
787 264, "tx frames 256-511",
788 272, "tx frames 512-1023",
789 280, "tx frames 1024-1518",
790 288, "tx frames 1519-mtu",
794 320, "tx excess coll",
796 336, "tx single col",
800 static uint phypwr[] = {1<<26, 1<<27};
801 static uint coma[] = {1<<28, 1<<29};
802 static uchar nilea[Eaddrlen];
804 static Ctlr *ctlrtab[Nctlr];
813 uchar pad[128]; /* cacheline */
827 return k->event != 0;
840 sleep(k, icansleep, k);
845 getslot(Sring *r, Kproc *k)
847 if(r->rp + r->m - r->wp & ~r->m)
849 return r->r + (r->wp++ & r->m);
853 getnslot(Sring *r, uint *wp, Status **t, uint n)
857 if(r->rp + r->m - (n - 1) - wp[0] & ~r->m)
859 for(i = 0; i < n; i++)
860 t[i] = r->r + (wp[0]++ & r->m);
864 /* assume allocs come from a single thread; 30*0.999x speedup */
870 if((b = rbtab[t].x) != nil){
872 rbtab[t].x = b->next;
879 b = rbtab[t].x = rbtab[t].b;
887 rbtab[t].x = b->next;
895 rbfree(Block *b, int t)
897 b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, Rbalign);
898 b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
900 b->next = rbtab[t].b;
901 if(b->next == nil && rbtab[t].starve){
903 unstarve(rbtab[t].k);
933 static Freefn freetab[Nctlr] = {
941 macread32(Ctlr *c, uint r)
943 return c->reg[c->portno*0x20 + r];
947 macwrite32(Ctlr *c, uint r, uint v)
949 c->reg[c->portno*0x20 + r] = v;
953 macread16(Ctlr *c, uint r)
955 return c->reg16[c->portno*0x40 + r];
959 macwrite16(Ctlr *c, uint r, uint v)
961 c->reg16[c->portno*0x40 + r] = v;
965 macread8(Ctlr *c, uint r)
967 return c->reg8[c->portno*0x80 + r];
971 macwrite8(Ctlr *c, uint r, uint v)
973 c->reg8[c->portno*0x80 + r] = v;
976 static uint gmac32[2] = {
982 gmacread32(Ctlr *c, uint r)
984 return c->reg[gmac32[c->portno] + r];
988 gmacwrite32(Ctlr *c, uint r, uint v)
990 c->reg[gmac32[c->portno] + r] = v;
993 static uint gmac[2] = {
999 gmacread(Ctlr *c, uint r)
1001 return c->reg16[gmac[c->portno] + r];
1005 gmacwrite(Ctlr *c, uint r, ushort v)
1007 c->reg16[gmac[c->portno] + r] = v;
1011 qrread(Ctlr *c, uint r)
1013 return c->reg[Qbase + c->portno*Qportsz + r>>2];
1017 qrwrite(Ctlr *c, uint r, uint v)
1019 c->reg[Qbase + c->portno*Qportsz + r>>2] = v;
1023 qrread16(Ctlr *c, uint r)
1025 return c->reg16[Qbase + c->portno*Qportsz + r>>1];
1029 qrwrite16(Ctlr *c, uint r, uint v)
1031 c->reg16[Qbase + c->portno*Qportsz + r>>1] = v;
1035 qrread8(Ctlr *c, uint r)
1037 return c->reg8[Qbase + c->portno*Qportsz + r>>0];
1041 qrwrite8(Ctlr *c, uint r, uint v)
1043 c->reg8[Qbase + c->portno*Qportsz + r>>0] = v;
1047 rrread32(Ctlr *c, uint r)
1049 return c->reg[Rbase + c->portno*Qportsz + r>>2];
1053 rrwrite32(Ctlr *c, uint r, uint v)
1055 c->reg[Rbase + c->portno*Qportsz + r>>2] = v;
1059 rrwrite8(Ctlr *c, uint r, uint v)
1061 c->reg8[Rbase + c->portno*Qportsz + r] = v;
1065 rrread8(Ctlr *c, uint r)
1067 return c->reg8[Rbase + c->portno*Qportsz + r];
1071 prread32(Ctlr *c, uint r)
1073 return c->reg[Pbase + c->portno*Qportsz + r>>2];
1077 prwrite32(Ctlr *c, uint r, uint v)
1079 c->reg[Pbase + c->portno*Qportsz + r>>2] = v;
1083 prread16(Ctlr *c, uint r)
1085 return c->reg16[Pbase + c->portno*Qportsz + r>>1];
1089 prwrite16(Ctlr *c, uint r, uint v)
1091 c->reg16[Pbase + c->portno*Qportsz + r>>1] = v;
1095 phyread(Ctlr *c, uint r)
1099 gmacwrite(c, Smictl, Smiread | r<<6);
1101 v = gmacread(c, Smictl);
1105 return gmacread(c, Smidata);
1111 phywrite(Ctlr *c, uint r, ushort v)
1113 gmacwrite(c, Smidata, v);
1114 gmacwrite(c, Smictl, Smiwrite | r<<6);
1116 v = gmacread(c, Smictl);
1119 if((v & Smibusy) == 0)
1120 return gmacread(c, Smidata);
1125 static uvlong lorder = 0x0706050403020100ull;
1128 getle(uchar *t, int w)
1134 for(i = w; i != 0; )
1140 putle(uchar *t, uvlong r, int w)
1146 o = (uchar*)&lorder;
1147 for(i = 0; i < w; i++)
1152 bufinit(Ctlr *c, uint q, uint start, uint end)
1156 rrwrite8(c, q + Rctl, Rrstclr);
1157 rrwrite32(c, q + Rstart, start);
1158 rrwrite32(c, q + Rend, end-1);
1159 rrwrite32(c, q + Rwp, start);
1160 rrwrite32(c, q + Rrp, start);
1162 if(q == Qr || q == Qr + Qportsz){
1164 rrwrite32(c, q + Rpon, t - 8192/8);
1165 rrwrite32(c, q + Rpoff, t - 16384/8);
1167 rrwrite8(c, q + Rctl, Rsfon);
1168 rrwrite8(c, q + Rctl, Renable);
1169 rrread8(c, q + Rctl);
1173 qinit(Ctlr *c, uint queue)
1175 qrwrite(c, queue + Qcsr, Qallclr);
1176 qrwrite(c, queue + Qcsr, Qgo);
1177 qrwrite(c, queue + Qcsr, Qfifoon);
1178 qrwrite16(c, queue + Qwm, 0x600); /* magic */
1179 // qrwrite16(c, queue + Qwm, 0x80); /* pcie magic; assume pcie; no help */
1182 /* initialized prefetching */
1184 pinit(Ctlr *c, uint queue, Sring *r)
1191 prwrite32(c, queue + Pctl, Prefrst);
1192 prwrite32(c, queue + Pctl, Prefrstclr);
1193 putle(u.u, Pciwaddrh(r->r), 4);
1194 prwrite32(c, queue + Paddrh, u.l);
1195 putle(u.u, Pciwaddrl(r->r), 4);
1196 prwrite32(c, queue + Paddrl, u.l);
1197 prwrite16(c, queue + Plidx, r->m);
1198 prwrite32(c, queue + Pctl, Prefon);
1199 prread32(c, queue + Pctl);
1216 pinit(c, Qtx, &c->tx);
1220 linkup(Ctlr *c, uint w)
1225 gmacwrite(c, Ctl, w|gmacread(c, Ctl));
1249 if((b = qbread(e->oq, 100000)) == nil)
1251 if(Pciwaddrh(b->rp) != 0){
1254 t->op = Oaddr64 | Hw;
1255 putle(t->status, Pciwaddrh(b->rp), 4);
1258 c->tbring[t - r->r] = b;
1259 putle(t->status, Pciwaddrl(b->rp), 4);
1260 putle(t->l, BLEN(b), 2);
1264 prwrite16(c, Qtx + Pputidx, r->wp & r->m);
1266 print("#l%d: tproc: queue closed\n", e->ctlrno);
1267 pexit("queue closed", 1);
1284 for(i = 0; i < Nrb; i++){
1285 b = allocb(c->rbsz + Rbalign);
1286 b->free = freetab[c->qno];
1291 if(c->type == Yukecu && (c->rev == 2 || c->rev == 3))
1292 qrwrite(c, Qr + Qtest, Qramdis);
1293 pinit(c, Qr, &c->rx);
1295 if((c->flag & Fnewle) == 0){
1296 t = getslot(r, &c->rxmit);
1297 putle(t->status, 14<<16 | 14, 4);
1300 qrwrite(c, Qr + Qcsr, Qsumen);
1302 macwrite32(c, Gfrxctl, Gftroff);
1306 #include "yukdump.h"
1308 rxscrew(Ether *e, Sring *r, Status *t, uint wp)
1313 if(wp - r->rp > r->cnt){
1314 print("rxscrew1 wp %ud(%ud) rp %ud %lud\n", wp, r->wp, r->rp, t-r->r);
1317 if(c->rbring[t - r->r]){
1318 print("rxscrew2 wp %ud rp %ud %lud\n", wp, r->rp, t-r->r);
1319 descriptorfu(e, Qr);
1326 replenish(Ether *e, Ctlr *c)
1340 lim = 128; /* hw limit? */
1341 for(n = 0; n < lim; n++){
1342 b = rballoc(c->qno);
1343 if(b == nil || getnslot(r, &wp, tab, req) == -1){
1349 putle(t->status, Pciwaddrh(b->wp), 4);
1351 t->op = Oaddr64 | Hw;
1354 if(rxscrew(e, r, t, wp) == -1)
1356 assert(c->rbring[t - r->r] == nil);
1357 c->rbring[t - r->r] = b;
1359 putle(t->status, Pciwaddrl(b->wp), 4);
1360 putle(t->l, c->rbsz, 2);
1366 prwrite16(c, Qr + Pputidx, wp & r->m);
1368 dprint("yuk: replenish %d %ud-%ud [%d-%d]\n", n, r->rp, wp, r->rp&r->m, wp&r->m);
1370 return lim - n == 0;
1389 if(replenish(e, c) == 0){
1391 print("yuk: rx unstarve?\n");
1396 promiscuous(void *a, int on)
1404 r = gmacread(c, Rxctl);
1406 r &= ~(Ufilter|Mfilter);
1408 r |= Ufilter|Mfilter;
1409 gmacwrite(c, Rxctl, r);
1412 static uchar pauseea[] = {1, 0x80, 0xc2, 0, 0, 1};
1415 multicast(void *a, uchar *ea, int on)
1425 r = gmacread(c, Rxctl);
1427 for(ll = &c->mc; *ll != nil; ll = &(*ll)->next)
1428 if(memcmp((*ll)->ea, ea, Eaddrlen) == 0)
1430 *ll = malloc(sizeof **ll);
1431 memmove((*ll)->ea, ea, Eaddrlen);
1433 for(p = nil, l = c->mc; l != nil; p = l, l = l->next)
1434 if(memcmp(l->ea, ea, Eaddrlen) == 0)
1444 memset(f, 0, sizeof f);
1445 if(0 /* flow control */){
1446 b = ethercrc(pauseea, Eaddrlen) & 0x3f;
1447 f[b>>3] |= 1 << (b & 7);
1449 for(l = c->mc; l != nil; l = l->next){
1450 b = ethercrc(l->ea, Eaddrlen) & 0x3f;
1451 f[b>>3] |= 1 << (b & 7);
1453 for(i = 0; i < sizeof f / 2; i++)
1454 gmacwrite(c, Mchash + 2*i, f[i] | f[i+1]<<8);
1455 gmacwrite(c, Rxctl, r | Mfilter);
1458 static int spdtab[4] = {
1469 i = phyread(c, Phyint);
1470 s = phyread(c, Phylstat);
1471 dprint("#l%d: yuk: link %.8ux %.8ux\n", e->ctlrno, i, s);
1473 e->link = (s & Plink) != 0;
1474 if(e->link && c->feat&Ffiber)
1482 dprint("#l%d: yuk: link %d spd %d\n", e->ctlrno, e->link, e->mbps);
1486 txcleanup(Ctlr *c, uint end)
1495 for(rp = rp0; rp != end; rp = r->rp & r->m){
1498 if((t->ctl & Eop) == 0)
1501 c->tbring[rp] = nil;
1505 if(r->wp - r->rp > 16){ /* BOTCH */
1506 print("TX unstarve %ud - %ud \n", r->wp, r->rp);
1507 unstarve(&c->txmit);
1512 rx(Ether *e, uint l, uint x, uint flag)
1528 cnt = x>>16 & 0x7fff;
1529 if(cnt != l || x&Rxerror &&
1530 !(c->type == Yukfep && c->rev == 0)){
1531 print("#l%d: yuk rx error %.4ux\n", e->ctlrno, x&0xffff);
1535 b->lim = b->wp; /* lie like a dog */
1543 cksum(Ctlr *c, uint ck, uint css)
1545 if(c->flag & Fnewle && css&(Cisip4|Cisip6) && css&Ctcpok)
1546 return Bipck | Btcpck | Budpck;
1547 else if(ck == 0xffff || ck == 0)
1555 uint i, p, lim, op, l, x;
1559 static uint ck = Badck;
1566 if((r->rp & r->m) == lim){
1567 lim = c->reg16[Stathd];
1568 if((r->rp & r->m) == lim)
1579 ck = getle(s->status, 4) & 0xffff;
1583 x = getle(s->status, 4);
1584 rx(e, l, x, cksum(c, ck, s->ctl));
1590 x = getle(s->status, 4);
1591 txcleanup(c, x & 0xfff);
1593 x = l>>24 & 0xff | l<< 8;
1595 if(x != 0 && c->oport)
1596 txcleanup(c->oport, x);
1599 print("#l%d: yuk: funny opcode %.2ux\n", e->ctlrno, op);
1605 while(p && replenish(e, c) != 0)
1607 c->reg[Statctl] = Statirqclr;
1616 hwerror(Ether *e, uint cause)
1622 cause = c->reg[Hwe];
1624 print("hwe: no cause\n");
1626 c->reg8[Tgc] = Tgclr;
1629 if(cause & (Hmerr | Hstatus)){
1630 c->reg8[Tstctl1] = Tstwen;
1631 u = pcicfgr16(c->p, PciPSR) | 0x7800;
1632 pcicfgw16(c->p, PciPSR, u);
1633 c->reg8[Tstctl1] = Tstwdis;
1634 cause &= ~(Hmerr | Hstatus);
1637 c->reg8[Tstctl1] = Tstwen;
1638 c->reg[Pciaer + Pciunc>>2] = ~0;
1639 u = c->reg[Pciaer + Pciunc>>2];
1641 print("#l%d: pcierror %.8ux\n", e->ctlrno, u);
1642 c->reg8[Tstctl1] = Tstwdis;
1645 if(cause & Hrxparity){
1646 print("#l%d: ram parity read error. bug? ca %.8ux\n", e->ctlrno, cause);
1647 qrwrite(c, Qtx + Qcsr, Qcirqpar);
1648 cause &= ~Hrxparity;
1650 if(cause & Hrparity){
1651 print("#l%d: ram parity read error. bug? ca %.8ux\n", e->ctlrno, cause);
1652 descriptorfu(e, Qr);
1653 descriptorfu(e, Qtx);
1654 c->reg16[Rictl + c->portno*0x40>>1] = Rirpclr;
1657 if(cause & Hwparity){
1658 print("#l%d: ram parity write error. bug? ca %.8ux\n", e->ctlrno, cause);
1659 descriptorfu(e, Qr);
1660 descriptorfu(e, Qtx);
1661 c->reg16[Rictl + c->portno*0x40>>1] = Riwpclr;
1664 if(cause & Hmfault){
1665 print("#l%d: mac parity error\n", e->ctlrno);
1666 macwrite32(c, Gmfctl, Gmfcpe);
1670 print("#l%d: leftover hwe %.8ux\n", e->ctlrno, cause);
1680 cause = macread8(c, Irq);
1681 cause &= ~(Rxdone | Txdone);
1684 print("#l%d: mac error %.8ux\n", e->ctlrno, cause);
1686 gmacread32(c, Txirq);
1690 gmacread32(c, Rxirq);
1694 macwrite32(c, Gfrxctl, Gmfcfu);
1698 macwrite32(c, Gmfctl, Gmfcfu);
1702 print("#l%d: leftover mac error %.8ux\n", e->ctlrno, cause);
1713 Irx<<Iphy2base, Qr + 0x80, "qr1",
1714 Itxs<<Iphy2base, Qtxs + 0x100, "qtxs1",
1715 Itx<<Iphy2base, Qtx + 0x100, "qtx1",
1719 eerror(Ether *e, uint cause)
1730 if(cause & (Irx | Itxs | Itx)*(1 | 1<<Iphy2base))
1731 for(i = 0; i < nelem(emap); i++){
1732 if((cause & emap[i].i) == 0)
1735 o = prread16(c, q + Pgetidx);
1736 print("#l%d: yuk: bug: %s: @%d ca=%.8ux\n",
1737 e->ctlrno, emap[i].s, o, cause);
1739 qrwrite(c, emap[i].q + Qcsr, Qcirqck);
1740 cause &= ~emap[i].i;
1743 print("#l%d: leftover error %.8ux\n", e->ctlrno, cause);
1761 cause = c->reg[Eisr];
1767 eerror(e, cause & Ierror);
1776 interrupt(Ureg*, void *v)
1785 cause = c->reg[Isrc2];
1786 if(cause != 0 && cause != ~0)
1787 unstarve(&c->iproc);
1793 if(c->type == Yukex && c->rev != 1
1794 || c->type == Yukfep
1795 || c->type == Yuksup)
1796 macwrite32(c, Gmfctl, Gmfjon | Gmfsfon);
1798 macwrite32(c, Gmfae, 0x8000 | 0x70); /* tx gmac fifo */
1799 macwrite32(c, Gmfctl, Gmfsfoff);
1808 if(ram = c->reg8[Ramcnt] * 4096/8){ /* in qwords */
1810 rx = ROUNDUP((2*ram)/3, 1024/8);
1811 bufinit(c, Qr, 0, rx);
1812 bufinit(c, Qtx, rx, ram);
1813 rrwrite8(c, Qtxs + Rctl, Rrst); /* sync tx off */
1815 macwrite8(c, Rxplo, 768/8);
1816 macwrite8(c, Rxphi, 1024/8);
1839 snprint(buf, sizeof buf, "#l%dtproc", e->ctlrno);
1840 kproc(buf, tproc, e);
1841 snprint(buf, sizeof buf, "#l%drproc", e->ctlrno);
1842 kproc(buf, rproc, e);
1843 snprint(buf, sizeof buf, "#l%diproc", e->ctlrno);
1844 kproc(buf, iproc, e);
1846 c->reg[Ism] |= Ibmu | Iport<<Iphy2base*c->portno;
1850 ifstat(Ether *e0, void *a, long n, ulong offset)
1858 p = s = malloc(READSTR);
1860 for(i = 0; i < nelem(stattab); i++){
1861 u = gmacread32(c, Stats + stattab[i].offset/4);
1863 p = seprint(p, e, "%s\t%ud\n", stattab[i].name, u);
1865 p = seprint(p, e, "stat %.4ux ctl %.3ux\n", gmacread(c, Stat), gmacread(c, Ctl));
1866 p = seprint(p, e, "irq %.8ux\n", c->reg[Isrc2]);
1867 p = seprint(p, e, "pref %.8ux %.4ux\n", prread32(c, Qr + Pctl), prread16(c, Qr + Pgetidx));
1868 p = seprint(p, e, "nfast %ud nslow %ud\n", rbtab[c->qno].nfast, rbtab[c->qno].nslow);
1870 p = dumppci(c, p, e);
1871 p = dumpgmac(c, p, e);
1872 p = dumpmac(c, p, e);
1873 p = dumpreg(c, p, e);
1875 seprint(p, e, "%s rev %d phy %s\n", idtab[c->type].name,
1876 c->rev, c->feat&Ffiber? "fiber": "copper");
1877 n = readstr(offset, a, n, s);
1882 static Cmdtab ctltab[] = {
1884 2, "descriptorfu", 1,
1888 ctl(Ether *e, void *buf, long n)
1893 cb = parsecmd(buf, n);
1898 t = lookupcmd(cb, ctltab, nelem(ctltab));
1904 descriptorfu(e, Qr);
1913 yukpcicfgr32(Ctlr *c, uint r)
1915 return c->reg[r + 0x1c00>>2];
1919 yukpcicfgw32(Ctlr *c, uint r, uint v)
1921 c->reg[r + 0x1c00>>2] = v;
1929 u = u0 = yukpcicfgr32(c, Pciphy);
1930 u &= ~phypwr[c->portno];
1931 if(c->type == Yukxl && c->rev > 1)
1932 u |= coma[c->portno];
1934 c->reg8[Tstctl1] = Tstwen;
1935 yukpcicfgw32(c, Pciphy, u);
1936 c->reg8[Tstctl1] = Tstwdis;
1938 if(c->type == Yukfe)
1939 c->reg8[Phyctl] = Aneen;
1940 else if(c->flag & Fapwr)
1941 macwrite32(c, Phy, Gphyrstclr);
1949 if((c->feat & Fnewphy) == 0){
1950 u = phyread(c, Phyextctl);
1951 u &= ~0xf70; /* clear downshift counters */
1952 u |= 0x7<<4; /* mac tx clock = 25mhz */
1953 if(c->type == Yukec)
1954 u |= 2*Dnmstr | Dnslv;
1957 phywrite(c, Phyextctl, u);
1959 u = phyread(c, Phyphy);
1961 /* questionable value */
1962 if(c->feat & Ffiber)
1964 else if(c->feat & Fgbe){
1967 if(c->flag & Fnewphy){
1969 // u |= 2*(1<<12) | 1<<11; /* like 2*Dnmstr | Dnslv */
1970 u |= 2*(1<<9) | 1<<11;
1973 u |= Ppmdixa >> 1; /* why the shift? */
1974 if(c->type == Yukfep && c->rev == 0){
1978 phywrite(c, Phyphy, u);
1979 /* copper/fiber specific stuff gmacwrite(c, Ctl, 0); */
1980 gmacwrite(c, Ctl, 0);
1982 if(c->feat & Ffiber)
1983 phywrite(c, Gbectl, Gbexf | Gbexh);
1985 phywrite(c, Gbectl, Gbef | Gbeh);
1986 phywrite(c, Phyana, Anall);
1987 phywrite(c, Phyctl, Phyrst | Anerst | Aneen);
1988 /* chip specific stuff? */
1989 if (c->type == Yukfep){
1990 u = phyread(c, Phyphy) | Ppnpe;
1991 u &= ~(Ppengy | Ppscrdis);
1992 phywrite(c, Phyphy, u);
1993 // phywrite(c, 0x16, 0x0b54); /* write to fe_led_par */
1995 /* yukfep and rev 0: apply workaround for integrated resistor calibration */
1996 phywrite(c, Phypadr, 17);
1997 phywrite(c, 0x1e, 0x3f60);
1999 phywrite(c, Phyintm, Anok | Anerr | Lsc);
2000 dprint("phyid %.4ux step %.4ux\n", phyread(c, 2), phyread(c, 3));
2008 pcicfgw32(c->p, Pciclk, 0);
2009 c->reg16[Ctst] = Swclr;
2011 c->type = c->reg8[Chip] - 0xb3;
2012 c->rev = c->reg8[Maccfg]>>4 & 0xf;
2015 if(idtab[c->type].okrev != 0xff)
2016 if(c->rev != idtab[c->type].okrev)
2018 c->feat |= idtab[c->type].feat;
2021 if(t == 'L' || t == 'S' || t == 'P')
2024 /* check second port ... whatever */
2029 µ2clk(Ctlr *c, int µs)
2031 return idtab[c->type].mhz * µs;
2035 gmacsetea(Ctlr *c, uint r)
2041 for(i = 0; i < Eaddrlen; i += 2)
2042 gmacwrite(c, r + i, ra[i + 0] | ra[i + 1]<<8);
2053 if(c->type == Yukex)
2054 c->reg16[Asfcs/2] &= ~(Asfbrrst | Asfcpurst | Asfucrst);
2056 c->reg8[Asfcs] = Asfrst;
2057 c->reg16[Ctst] = Asfdis;
2059 c->reg16[Ctst] = Swrst;
2060 c->reg16[Ctst] = Swclr;
2062 c->reg8[Tstctl1] = Tstwen;
2063 pcicfgw16(c->p, PciPSR, pcicfgr16(c->p, PciPSR) | 0xf100);
2064 c->reg16[Ctst] = Mstrclr;
2065 /* fixup pcie extended error goes here */
2067 c->reg8[Pwrctl] = Vauxen | Vccen | Vauxoff | Vccon;
2068 c->reg[Clkctl] = Clkdivdis;
2069 if(c->type == Yukxl && c->rev > 1)
2070 c->reg8[Clkgate] = ~Link2inactive;
2072 c->reg8[Clkgate] = 0;
2073 if(c->flag & Fapwr){
2074 pcicfgw32(c->p, Pciclk, 0);
2075 pcicfgw32(c->p, Pciasp, pcicfgr32(c->p, Pciasp) & Aspmsk);
2076 pcicfgw32(c->p, Pcistate, pcicfgr32(c->p, Pcistate) & Vmain);
2077 pcicfgw32(c->p, Pcicf1, 0);
2078 c->reg[Gpio] |= Norace;
2079 print("yuk2: advanced power %.8ux\n", c->reg[Gpio]);
2081 c->reg8[Tstctl1] = Tstwdis;
2083 for(i = 0; i < c->nports; i++){
2084 macwrite8(c, Linkctl, Linkrst);
2085 macwrite8(c, Linkctl, Linkclr);
2086 if(c->type == Yukex || c->type == Yuksup)
2087 macwrite16(c, Mac, Nomacsec | Nortx);
2090 c->reg[Dpolltm] = Pollstop;
2092 for(i = 0; i < c->nports; i++)
2093 macwrite8(c, Txactl, Txaclr);
2094 for(i = 0; i < c->nports; i++){
2095 c->reg8[i*64 + Rictl] = Riclr;
2096 for(j = 0; j < 12; j++)
2097 c->reg8[i*64 + Rib + j] = 36; /* qword times */
2100 c->reg[Hwem] = Hdflt;
2101 macwrite8(c, Irqm, 0);
2102 for(i = 0; i < 4; i++)
2103 gmacwrite(c, Mchash + 2*i, 0);
2104 gmacwrite(c, Rxctl, Ufilter | Mfilter | Rmcrc);
2106 for(i = 0; i < nelem(c->tbring); i++)
2107 if(b = c->tbring[i]){
2111 for(i = 0; i < nelem(c->rbring); i++)
2112 if(b = c->rbring[i]){
2117 memset(c->tbring, 0, sizeof c->tbring[0] * nelem(c->tbring));
2118 memset(c->rbring, 0, sizeof c->rbring[0] * nelem(c->rbring));
2119 memset(c->tx.r, 0, sizeof c->tx.r[0] * c->tx.cnt);
2120 memset(c->rx.r, 0, sizeof c->rx.r[0] * c->rx.cnt);
2121 memset(c->status.r, 0, sizeof c->status.r[0] * c->status.cnt);
2122 c->reg[Statctl] = Statrst;
2123 c->reg[Statctl] = Statclr;
2124 c->reg[Stataddr + 0] = Pciwaddrl(c->status.r);
2125 c->reg[Stataddr + 4] = Pciwaddrh(c->status.r);
2126 c->reg16[Stattl] = c->status.m;
2127 c->reg16[Statth] = 10;
2128 c->reg8[Statwm] = 16;
2129 if(c->type == Yukxl && c->rev == 0)
2130 c->reg8[Statiwm] = 4;
2132 c->reg8[Statiwm] = 4; //16;
2134 /* set transmit, isr, level timers */
2135 c->reg[Tsti] = µ2clk(c, 1000);
2136 c->reg[Titi] = µ2clk(c, 20);
2137 c->reg[Tlti] = µ2clk(c, 100);
2139 c->reg[Statctl] = Staton;
2141 c->reg8[Tstc] = Tstart;
2142 c->reg8[Tltc] = Tstart;
2143 c->reg8[Titc] = Tstart;
2153 r = macread32(c, Phy) & ~(Gphyrst | Gphyrstclr);
2154 macwrite32(c, Phy, r | Gphyrst);
2155 macwrite32(c, Phy, r | Gphyrstclr);
2156 /* macwrite32(c, Mac, Macrst); ? */
2157 macwrite32(c, Mac, Macrstclr);
2159 if(c->type == Yukxl && c->rev == 0 && c->portno == 1){
2163 macwrite8(c, Irqm, Txurun);
2168 gmacwrite(c, Phyaddr, (r = gmacread(c, Phyaddr)) | Mibclear);
2169 for(i = 0; i < nelem(stattab); i++)
2170 gmacread32(c, Stats + stattab[i].offset/4);
2171 gmacwrite(c, Phyaddr, r);
2173 gmacwrite(c, Txctl, 4<<10); /* collision distance */
2174 gmacwrite(c, Txflow, 0xffff); /* flow control */
2175 gmacwrite(c, Txparm, 3<<14 | 0xb<<9 | 0x1c<<4 | 4);
2176 gmacwrite(c, Rxctl, Ufilter | Mfilter | Rmcrc);
2177 gmacwrite(c, Serctl, 0x04<<11 /* blind */ | Jumboen | 0x1e /* ipig */);
2182 gmacwrite(c, Txmask, 0);
2183 gmacwrite(c, Rxmask, 0);
2184 gmacwrite(c, Trmask, 0);
2186 macwrite32(c, Gfrxctl, Gfrstclr);
2188 if(c->type == Yukex || c->type == Yukfep)
2190 macwrite32(c, Gfrxctl, r);
2191 if(c->type == Yukxl)
2192 macwrite32(c, Grxfm, 0);
2194 macwrite32(c, Grxfm, Ferror);
2195 if(c->type == Yukfep && c->rev == 0)
2196 macwrite32(c, Grxft, 0x178);
2198 macwrite32(c, Grxft, 0xb);
2200 macwrite32(c, Gmfctl, Gmfclr); /* clear reset */
2201 macwrite32(c, Gmfctl, Gmfon); /* on */
2204 if(c->type == Yukfep && c->rev == 0)
2205 c->reg[Gmfea] = c->reg[Gmfea] & ~3;
2212 slice(void **v, uint r, uint sz)
2218 *v = (void*)(a + sz);
2223 setupr(Sring *r, uint cnt)
2239 c->io = p->mem[0].bar&~0xf;
2240 mem = vmap(c->io, p->mem[0].size);
2242 print("yuk: cant map %#p\n", c->io);
2246 c->reg = (uint*)mem;
2247 c->reg8 = (uchar*)mem;
2248 c->reg16 = (ushort*)mem;
2249 if(memcmp(c->ra, nilea, sizeof c->ra) == 0)
2250 memmove(c->ra, c->reg8 + Macadr + 8*c->portno, Eaddrlen);
2252 setupr(&c->status, Sringcnt);
2253 setupr(&c->tx, Tringcnt);
2254 setupr(&c->rx, Rringcnt);
2256 n = sizeof c->status.r[0] * (c->status.cnt + c->tx.cnt + c->rx.cnt);
2257 n += 16*4096*2; /* rounding slop */
2258 c->alloc = xspanalloc(n, 16*4096, 0); /* unknown alignment constraints */
2259 memset(c->alloc, 0, n);
2262 c->status.r = slice(&v, 16*4096, sizeof c->status.r[0] * c->status.cnt);
2263 c->tx.r = slice(&v, 16*4096, sizeof c->tx.r[0] * c->tx.cnt);
2264 c->rx.r = slice(&v, 16*4096, sizeof c->rx.r[0] * c->rx.cnt);
2266 c->nports = 1; /* BOTCH */
2269 print("yuk: cant reset\n");
2272 vunmap(mem, p->mem[0].size);
2290 vunmap(c->reg, p->mem[0].size);
2302 for(p = nil; p = pcimatch(p, 0, 0); ){
2303 for(i = 0; i < nelem(vtab); i++)
2304 if(vtab[i].vid == p->vid)
2305 if(vtab[i].did == p->did)
2307 if(i == nelem(vtab))
2309 if(nctlr == nelem(ctlrtab)){
2310 print("yuk: too many controllers\n");
2313 c = malloc(sizeof *c);
2316 rbtab[c->qno].k = &c->rxmit;
2317 c->rbsz = vtab[i].mtu;
2318 ctlrtab[nctlr++] = c;
2334 if(c == nil || c->flag&Fprobe)
2336 if(e->port != 0 && e->port != (ulong)c->reg)
2345 e->irq = c->p->intl;
2346 e->tbdf = c->p->tbdf;
2348 e->maxmtu = c->rbsz;
2349 memmove(e->ea, c->ra, Eaddrlen);
2354 e->interrupt = interrupt;
2355 e->multicast = multicast;
2356 e->promiscuous = promiscuous;
2357 e->shutdown = shutdown;
2366 addethercard("yuk", pnp);