2 * marvell 88e8057 yukon2
3 * copyright © 2009-10 erik quanstrom
6 #include "../port/lib.h"
11 #include "../port/pci.h"
12 #include "../port/error.h"
13 #include "../port/netif.h"
14 #include "../port/etherif.h"
16 #define Pciwaddrh(x) 0
17 #define Pciwaddrl(x) PCIWADDR(x)
18 #define is64() (sizeof(uintptr) == 8)
19 #define dprint(...) if(debug) print(__VA_ARGS__); else {}
21 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 */
54 Macadr = 0x0100, /* mac address 2ports*3 */
58 Ramcnt = 0x011c, /* # of 4k blocks */
66 Rictl = 0x01a0, /* ri ram buffer ctl */
67 Rib = 0x0190, /* ri buffer0 */
69 /* other unoffset registers */
70 Asfcs = 0x0e68, /* asf command and status */
73 Statctl = 0x0e80/4, /* status */
74 Stattl = 0x0e84/2, /* tail (previous) status addr */
75 Stataddr = 0x0e88/4, /* status address low */
78 Statwm = 0x0eac, /* stat watermark */
79 Statiwm = 0x0ead, /* isr stat watermark */
81 Dpolltm = 0x0e08/4, /* descriptor pool timer */
84 Tgv = 0x0e14/4, /* gmac timer current value */
85 Tgc = 0x0e18, /* gmac timer ctl */
86 Tgt = 0x0e1a, /* gmac timer test */
88 Tsti = 0x0ec0/4, /* stat tx timer ini */
89 Tlti = 0x0eb0/4, /* level */
90 Titi = 0x0ed0/4, /* isr */
92 Tstc = 0x0ec8, /* stat tx timer ctl */
93 Tltc = 0x0eb8, /* level timer ctl */
94 Titc = 0x0ed8, /* isr timer ctl */
96 /* “gmac” registers */
103 Serctl = 0x018/2, /* serial mode */
104 Mchash = 0x034/2, /* 4 registers; 4 bytes apart */
106 /* interrupt sources and masks */
109 Trirq = 0x04c/2, /* tx/rx overflow irq source */
114 Smictl = 0x080/2, /* serial mode control */
118 Ea0 = 0x01c/2, /* 3 16 bit gmac registers */
124 Txactl = 0x210, /* transmit arbiter ctl */
126 Grxea = 0x0c40/4, /* rx fifo end address */
127 Gfrxctl = 0x0c48/4, /* gmac rxfifo ctl */
128 Grxfm = 0x0c4c/4, /* fifo flush mask */
129 Grxft = 0x0c50/4, /* fifo flush threshold */
130 Grxtt = 0x0c54/4, /* rx truncation threshold */
131 Gmfea = 0x0d40/4, /* end address */
132 Gmfae = 0x0d44/4, /* almost empty thresh */
133 Gmfctl = 0x0d48/4, /* tx gmac fifo ctl */
135 Rxphi = 0x0c58, /* pause high watermark */
136 Rxplo = 0x0c5c, /* pause low watermark */
143 Mac = 0x0f00/4, /* global mac control */
144 Phy = 0x0f04/4, /* phy control register */
146 Irq = 0x0f08, /* irq source */
147 Irqm = 0x0f0c, /* irq mask */
150 /* queue registers; all offsets from Qbase*/
152 Qportsz = 0x0080, /* BOTCH; tx diff is 2x rx diff */
165 Qcsr = 0x34, /* 32bit */
169 /* buffer registers; all offsets from Rbase */
176 Rpon = 0x10, /* pause frames on */
177 Rpoff = 0x14, /* pause frames off */
178 Rhon = 0x18, /* high-priority frames on */
179 Rhoff = 0x1c, /* high-priority frames off */
185 Plidx = 0x04, /* last addr; 16 bit */
188 Pgetidx = 0x10, /* 16 bit */
189 Pputidx = 0x14, /* 16 bit */
190 Pfifow = 0x20, /* 8 bit */
191 Pfifor = 0x24, /* 8 bit */
192 Pfifowm = 0x20, /* 8 bit */
194 /* indirect phy registers */
199 Phyana = 0x004, /* auto neg advertisement */
200 Phylpa = 0x005, /* link partner ability */
201 Phyanee = 0x006, /* auto neg adv expansion */
202 Phynp = 0x007, /* next page */
203 Phylnp = 0x008, /* link partner next page */
206 Phyphy = 0x010, /* phy specific ctl */
208 Phyintm = 0x012, /* phy interrupt mask */
211 Phyrxe = 0x015, /* rx error counter */
212 Phypage = 0x016, /* external address */
213 Phypadr = 0x01d, /* phy page address */
219 Aspglinkdn = 1<<14, /* gphy link down */
222 Aspmsk = Aspforce | Aspglinkdn | Aspfempty | Aspclkrun,
228 Sfast = 1<<15, /* 100mbit */
230 Txnofc = 1<<13, /* tx flow control disabled */
231 Link = 1<<12, /* link up */
232 Pausest = 1<<11, /* pause state */
236 Physc = 1<<5, /* phy status change */
237 Sgbe = 1<<4, /* gbe speed */
238 Rxnofc = 1<<2, /* rx flow control disabled */
239 Promisc = 1<<1, /* promiscuous mode enabled */
249 Fpass = 1<<6, /* "force link pass" ? */
252 Fasten = 1<<3, /* enable 100mbit */
253 Adudis = 1<<2, /* disable auto upd duplex */
254 Afcdis = 1<<1, /* disable auto upd flow ctl */
255 Aspddis = 1<<0, /* disable auto upd speed */
258 Ufilter = 1<<15, /* unicast filter */
259 Mfilter = 1<<14, /* multicast filter */
260 Rmcrc = 1<<13, /* remove frame crc */
270 /* Asfcs: yukex only */
271 Asfbrrst = 1<<9, /* bridge reset */
272 Asfcpurst = 1<<8, /* cpu reset */
273 Asfucrst = 3<<0, /* µctlr reset */
276 Asfhvos = 1<<4, /* os present */
290 Nomacsec = 1<<13 | 1<<11,
302 Txovfl = 1<<5, /* tx counter overflow */
303 Rxovfl = 1<<4, /* rx counter overflow */
304 Txurun = 1<<3, /* transmit fifo underrun */
305 Txdone = 1<<2, /* frame tx done */
306 Rxorun = 1<<1, /* rx fifo overrun */
307 Rxdone = 1<<0, /* frame rx done */
323 Asfdis = 1<<12, /* asf disable */
324 Clken = 1<<11, /* enable clock */
328 Mstopped = 1<<5, /* master is stopped */
329 Mstop = 1<<4, /* stop master */
330 Mstrclr = 1<<3, /* master reset clear */
331 Mstrrset = 1<<2, /* master reset */
354 /* csr interrupts: Isrc2, Eisr, etc. */
356 Ibmu = 1<<30, /* sring irq */
362 Itxs = 1<<1, /* descriptor error */
363 Itx = 1<<0, /* descriptor error */
367 Ierror = (Imac | Itx | Irx)*(1 | 1<<Iphy2base),
369 /* hwe interrupts: Hwe Hwem */
370 Htsof = 1<<29, /* timer stamp overflow */
372 Hmerr = 1<<27, /* master error */
373 Hstatus = 1<<26, /* status exception */
374 Hpcie = 1<<25, /* pcie error */
375 Hpcie2 = 1<<24, /* " */
377 Hrparity = 1<<5, /* ram read parity error */
378 Hwparity = 1<<4, /* ram write parity error */
379 Hmfault = 1<<3, /* mac fault */
380 Hrxparity = 1<<2, /* rx parity */
381 Htcptxs = 1<<1, /* tcp length mismatch */
382 Htcptxa = 1<<0, /* tcp length mismatch */
387 Hdflt = Htsof | Hmerr | Hstatus | Hmask*(H1base | H2base),
394 Link2inactive = 1<<7,
398 Phy100 = 1<<14, /* manual enable 100mbit */
399 Aneen = 1<<12, /* auto negotiation enable */
400 Phyoff = 1<<11, /* turn phy off */
401 Anerst = 1<<9, /* auto neg reset */
403 Phy1000 = 1<<5, /* manual enable gbe */
406 Annp = 1<<15, /* request next page */
407 Anack = 1<<14, /* ack rx (read only) */
408 Anrf = 1<<13, /* remote fault */
409 Anpa = 1<<11, /* try asymmetric pause */
410 Anp = 1<<10, /* try pause */
416 Anall = An100f | An100h | An10f | An10h | Anonly,
419 Gbef = 1<<9, /* auto neg gbe full */
420 Gbeh = 1<<8, /* auto neg gbe half */
421 Gbexf = 1<<6, /* auto neg gbe full fiber */
422 Gbexh = 1<<5, /* auto neg gbe full fiber */
425 Pptf = 3<<14, /* tx fifo depth */
426 Pprf = 3<<12, /* rx fifo depth */
427 Pped = 3<<8, /* energy detect */
428 Ppmdix = 3<<5, /* mdix conf */
429 Ppmdixa = 3<<5, /* automdix */
431 Ppengy = 1<<14, /* fe+ enable energy detect */
432 Ppscrdis = 1<<9, /* fe+ scrambler disable */
433 Ppnpe = 1<<12, /* fe+ enable next page */
438 Phypr = 1<<12, /* page rx */
439 Phydone = 1<<11, /* speed and duplex neg. done */
443 Pdwnsh = 1<<5, /* downshift */
444 Penergy = 1<<4, /* energy detect */
445 Ptxpause = 1<<3, /* tx pause enabled */
446 Prxpause = 1<<2, /* rx pause enabled */
447 Ppol = 1<<2, /* polarity */
448 Pjarjar = 1<<1, /* mesa no understasa */
451 Anerr = 1<<15, /* an error */
452 Lsp = 1<<14, /* link speed change */
453 Andc = 1<<13, /* an duplex change */
455 Lsc = 1<<10, /* link status change */
456 Symerr = 1<<9, /* symbol error */
457 Fcarr = 1<<8, /* false carrier */
461 Engych = 1<<4, /* energy change */
462 Dtech = 1<<2, /* dte power det status */
463 Polch = 1<<1, /* polarity change */
467 Dnmstr = 1<<9, /* master downshift; 0: 1x; 1: 2x; 2: 3x */
473 Tgclr = 1<<0, /* clear irq */
476 Tstwen = 1<<1, /* enable config reg r/w */
477 Tstwdis = 1<<0, /* disable config reg r/w */
489 Rsfon = 1<<5, /* enable store/fwd */
502 Qsumen = 1<<13, /* tcp/ip cksum */
504 Qcirqpar = 1<<11, /* clear irq on parity errors */
517 Qallclr = Qfiforst | Qfifooff | Qrstclr,
518 Qgo = Qcirqpar | Qcirqck | Qstart | Qfifoen | Qenable,
521 Qckoff = 1<<31, /* tx: auto checksum off */
523 Qramdis = 1<<24, /* rx: ram disable */
526 Prefon = 1<<3, /* prefetch on */
532 Hw = 0x80, /* bitmask */
533 Ock = 0x12, /* tcp checksum start */
538 Orxts = 0x61, /* rx timestamp */
542 Omacs = 0x6c, /* macsec */
552 Gfroon = 1<<19, /* flush on rx overrun */
554 Gffon = 1<<7, /* rx fifo flush mode on */
562 Gmfsfoff = 1<<31, /* disable store-forward (ec ultra) */
563 Gmfsfon = 1<<30, /* able store-forward (ec ultra) */
564 Gmfvon = 1<<25, /* vlan tag on */
565 Gmfvoff = 1<<24, /* vlan off */
566 Gmfjon = 1<<23, /* jumbo on (ec ultra) */
567 Gmfjoff = 1<<22, /* jumbo off */
568 Gmfcfu = 1<<6, /* clear fifio underrun irq */
569 Gmfcfc = 1<<5, /* clear frame complete irq */
570 Gmfcpe = 1<<4, /* clear parity error irq */
581 Fmc = 1<<10, /* multicast */
583 Fok = 1<<8, /* good frame */
587 Ftoobg = 1<<4, /* oversized */
588 Ffrag = 1<<3, /* fragment */
590 Ffifoof = 1<<0, /* fifo overflow */
591 Ferror = Ffifoof | Fcrcerr | Ffrag | Ftoobg
592 | Fmiierr | Fbadfc | Ftoosm | Fjabbr,
594 /* rx checksum bits in Status.ctl */
595 Badck = 5, /* arbitrary bad checksum */
597 Ctcpok = 1<<7, /* tcp or udp cksum ok */
601 /* more status ring rx bits */
603 Rxjab = 1<<12, /* jabber */
604 Rxsmall = 1<<11, /* too small */
605 Rxmc = 1<<10, /* multicast */
606 Rxbc = 1<<9, /* bcast */
608 Rxfcok = 1<<7, /* flow control pkt */
611 Rxbig = 1<<4, /* too big */
614 Rxfov = 1<<0, /* fifo overflow */
615 Rxerror = Rxfov | Rxcrcerr | Rxfrag | Rxbig | Rxmiierr
616 | Rxfcbad | Rxsmall | Rxjab,
626 Fancy =Fgbe | Fnewphy | Fapwr,
636 Yukba, /* doesn't exist */
641 typedef struct Chipid Chipid;
642 typedef struct Ctlr Ctlr;
643 typedef void (*Freefn)(Block*);
644 typedef struct Kproc Kproc;
645 typedef struct Mc Mc;
646 typedef struct Stattab Stattab;
647 typedef struct Status Status;
648 typedef struct Sring Sring;
649 typedef struct Vtab Vtab;
673 Ctlr *oport; /* port 2 */
696 Block *tbring[Tringcnt];
698 Block *rbring[Rringcnt];
728 static Chipid idtab[] = {
729 [Yukxl] Fgbe | Fnewphy, 0xff, 156, "yukon-2 xl",
730 [Yukecu] Fancy, 0xff, 125, "yukon-2 ec ultra",
731 [Yukex] Fancy | Fnewle, 0xff, 125, "yukon-2 extreme",
732 [Yukec] Fgbe, 2, 125, "yukon-2 ec",
733 [Yukfe] 0, 0xff, 100, "yukon-2 fe",
734 [Yukfep] Fnewphy|Fapwr | Fnewle, 0xff, 50, "yukon-2 fe+",
735 [Yuksup] Fgbe | Fnewphy | Fnewle, 0xff, 125, "yukon-2 supreme",
736 [Yukul2] Fgbe |Fapwr, 0xff, 125, "yukon-2 ultra2",
737 [Yukba] 0, 0, 0, "??",
738 [Yukopt] Fancy, 0xff, 125, "yukon-2 optima",
741 static Vtab vtab[] = {
742 0x11ab, 0x4354, 1514, "88e8040", /* unsure on mtu */
743 0x11ab, 0x4362, 1514, "88e8053",
744 0x11ab, 0x4363, 1514, "88e8055",
745 0x11ab, 0x4364, 1514, "88e8056",
746 0x11ab, 0x4380, 1514, "88e8057",
747 0x11ab, 0x436b, 1514, "88e8071", /* unsure on mtu */
748 0x1186, 0x4b00, 9000, "dge-560t",
749 0x1186, 0x4b02, 1514, "dge-550sx",
750 0x1186, 0x4b03, 1514, "dge-550t",
753 static Stattab stattab[] = {
765 80, "rx frames < 64",
766 88, "rx frames < 64 fcs",
768 104, "rx frames 65-127",
769 112, "rx frames 128-255",
770 120, "rx frames 256-511",
771 128, "rx frames 512-1023",
772 136, "rx frames 1024-1518",
773 144, "rx frames 1519-mtu",
774 152, "rx frames too long",
776 176, "rx fifo oflow",
787 248, "tx frames 65-127",
788 256, "tx frames 128-255",
789 264, "tx frames 256-511",
790 272, "tx frames 512-1023",
791 280, "tx frames 1024-1518",
792 288, "tx frames 1519-mtu",
796 320, "tx excess coll",
798 336, "tx single col",
802 static uint phypwr[] = {1<<26, 1<<27};
803 static uint coma[] = {1<<28, 1<<29};
804 static uchar nilea[Eaddrlen];
806 static Ctlr *ctlrtab[Nctlr];
815 return k->event != 0;
828 sleep(k, icansleep, k);
833 getnslot(Sring *r, uint *wp, Status **t, uint n)
837 if(r->m - (int)(wp[0] - r->rp) < n)
839 for(i = 0; i < n; i++)
840 t[i] = r->r + (wp[0]++ & r->m);
845 macread32(Ctlr *c, uint r)
847 return c->reg[c->portno*0x20 + r];
851 macwrite32(Ctlr *c, uint r, uint v)
853 c->reg[c->portno*0x20 + r] = v;
857 macread16(Ctlr *c, uint r)
859 return c->reg16[c->portno*0x40 + r];
863 macwrite16(Ctlr *c, uint r, uint v)
865 c->reg16[c->portno*0x40 + r] = v;
869 macread8(Ctlr *c, uint r)
871 return c->reg8[c->portno*0x80 + r];
875 macwrite8(Ctlr *c, uint r, uint v)
877 c->reg8[c->portno*0x80 + r] = v;
880 static uint gmac32[2] = {
886 gmacread32(Ctlr *c, uint r)
888 return c->reg[gmac32[c->portno] + r];
892 gmacwrite32(Ctlr *c, uint r, uint v)
894 c->reg[gmac32[c->portno] + r] = v;
897 static uint gmac[2] = {
903 gmacread(Ctlr *c, uint r)
905 return c->reg16[gmac[c->portno] + r];
909 gmacwrite(Ctlr *c, uint r, ushort v)
911 c->reg16[gmac[c->portno] + r] = v;
915 qrread(Ctlr *c, uint r)
917 return c->reg[Qbase + c->portno*Qportsz + r>>2];
921 qrwrite(Ctlr *c, uint r, uint v)
923 c->reg[Qbase + c->portno*Qportsz + r>>2] = v;
927 qrread16(Ctlr *c, uint r)
929 return c->reg16[Qbase + c->portno*Qportsz + r>>1];
933 qrwrite16(Ctlr *c, uint r, uint v)
935 c->reg16[Qbase + c->portno*Qportsz + r>>1] = v;
939 qrread8(Ctlr *c, uint r)
941 return c->reg8[Qbase + c->portno*Qportsz + r>>0];
945 qrwrite8(Ctlr *c, uint r, uint v)
947 c->reg8[Qbase + c->portno*Qportsz + r>>0] = v;
951 rrread32(Ctlr *c, uint r)
953 return c->reg[Rbase + c->portno*Qportsz + r>>2];
957 rrwrite32(Ctlr *c, uint r, uint v)
959 c->reg[Rbase + c->portno*Qportsz + r>>2] = v;
963 rrwrite8(Ctlr *c, uint r, uint v)
965 c->reg8[Rbase + c->portno*Qportsz + r] = v;
969 rrread8(Ctlr *c, uint r)
971 return c->reg8[Rbase + c->portno*Qportsz + r];
975 prread32(Ctlr *c, uint r)
977 return c->reg[Pbase + c->portno*Qportsz + r>>2];
981 prwrite32(Ctlr *c, uint r, uint v)
983 c->reg[Pbase + c->portno*Qportsz + r>>2] = v;
987 prread16(Ctlr *c, uint r)
989 return c->reg16[Pbase + c->portno*Qportsz + r>>1];
993 prwrite16(Ctlr *c, uint r, uint v)
995 c->reg16[Pbase + c->portno*Qportsz + r>>1] = v;
999 phyread(Ctlr *c, uint r)
1003 gmacwrite(c, Smictl, Smiread | r<<6);
1005 v = gmacread(c, Smictl);
1009 return gmacread(c, Smidata);
1015 phywrite(Ctlr *c, uint r, ushort v)
1017 gmacwrite(c, Smidata, v);
1018 gmacwrite(c, Smictl, Smiwrite | r<<6);
1020 v = gmacread(c, Smictl);
1023 if((v & Smibusy) == 0)
1024 return gmacread(c, Smidata);
1029 static uvlong lorder = 0x0706050403020100ull;
1032 getle(uchar *t, int w)
1038 for(i = w; i != 0; )
1044 putle(uchar *t, uvlong r, int w)
1050 o = (uchar*)&lorder;
1051 for(i = 0; i < w; i++)
1056 bufinit(Ctlr *c, uint q, uint start, uint end)
1060 rrwrite8(c, q + Rctl, Rrstclr);
1061 rrwrite32(c, q + Rstart, start);
1062 rrwrite32(c, q + Rend, end-1);
1063 rrwrite32(c, q + Rwp, start);
1064 rrwrite32(c, q + Rrp, start);
1066 if(q == Qr || q == Qr + Qportsz){
1068 rrwrite32(c, q + Rpon, t - 8192/8);
1069 rrwrite32(c, q + Rpoff, t - 16384/8);
1071 rrwrite8(c, q + Rctl, Rsfon);
1072 rrwrite8(c, q + Rctl, Renable);
1073 rrread8(c, q + Rctl);
1077 qinit(Ctlr *c, uint queue)
1079 qrwrite(c, queue + Qcsr, Qallclr);
1080 qrwrite(c, queue + Qcsr, Qgo);
1081 qrwrite(c, queue + Qcsr, Qfifoon);
1082 qrwrite16(c, queue + Qwm, 0x600); /* magic */
1083 // qrwrite16(c, queue + Qwm, 0x80); /* pcie magic; assume pcie; no help */
1086 /* initialized prefetching */
1088 pinit(Ctlr *c, uint queue, Sring *r)
1095 prwrite32(c, queue + Pctl, Prefrst);
1096 prwrite32(c, queue + Pctl, Prefrstclr);
1097 putle(u.u, Pciwaddrh(r->r), 4);
1098 prwrite32(c, queue + Paddrh, u.l);
1099 putle(u.u, Pciwaddrl(r->r), 4);
1100 prwrite32(c, queue + Paddrl, u.l);
1101 prwrite16(c, queue + Plidx, r->m);
1102 prwrite32(c, queue + Pctl, Prefon);
1103 prread32(c, queue + Pctl);
1120 pinit(c, Qtx, &c->tx);
1124 linkup(Ctlr *c, uint w)
1129 gmacwrite(c, Ctl, w|gmacread(c, Ctl));
1151 if((b = qbread(e->oq, 100000)) == nil)
1153 while(getnslot(r, &r->wp, tab, 1 + is64()) == -1)
1156 c->tbring[t - r->r] = b;
1160 t->op = Oaddr64 | Hw;
1161 putle(t->status, Pciwaddrh(b->rp), 4);
1163 putle(t->status, Pciwaddrl(b->rp), 4);
1164 putle(t->l, BLEN(b), 2);
1168 prwrite16(c, Qtx + Pputidx, r->wp & r->m);
1170 print("#l%d: tproc: queue closed\n", e->ctlrno);
1171 pexit("queue closed", 1);
1187 if(c->type == Yukecu && (c->rev == 2 || c->rev == 3))
1188 qrwrite(c, Qr + Qtest, Qramdis);
1189 pinit(c, Qr, &c->rx);
1191 if((c->flag & Fnewle) == 0){
1192 while(getnslot(r, &r->wp, &t, 1) == -1)
1194 putle(t->status, 14<<16 | 14, 4);
1197 qrwrite(c, Qr + Qcsr, Qsumen);
1199 macwrite32(c, Gfrxctl, Gftroff);
1203 #include "yukdump.h"
1205 rxscrew(Ether *e, Sring *r, Status *t, uint wp)
1210 if((int)(wp - r->rp) >= r->cnt){
1211 print("rxscrew1 wp %ud(%ud) rp %ud %zd\n", wp, r->wp, r->rp, t-r->r);
1214 if(c->rbring[t - r->r]){
1215 print("rxscrew2 wp %ud rp %ud %zd\n", wp, r->rp, t-r->r);
1216 descriptorfu(e, Qr);
1223 replenish(Ether *e, Ctlr *c)
1236 lim = 128; /* hw limit? */
1237 for(n = 0; n < lim; n++){
1238 b = iallocb(c->rbsz + Rbalign);
1239 if(b == nil || getnslot(r, &wp, tab, 1 + is64()) == -1){
1243 b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, Rbalign);
1246 if(rxscrew(e, r, t, wp) == -1){
1250 c->rbring[t - r->r] = b;
1254 putle(t->status, Pciwaddrh(b->wp), 4);
1256 t->op = Oaddr64 | Hw;
1258 putle(t->status, Pciwaddrl(b->wp), 4);
1259 putle(t->l, c->rbsz, 2);
1266 prwrite16(c, Qr + Pputidx, wp & r->m);
1267 dprint("yuk: replenish %d %ud-%ud [%d-%d]\n", n, r->rp, wp, r->rp&r->m, wp&r->m);
1286 if(replenish(e, c) == 0)
1292 promiscuous(void *a, int on)
1300 r = gmacread(c, Rxctl);
1302 r &= ~(Ufilter|Mfilter);
1304 r |= Ufilter|Mfilter;
1305 gmacwrite(c, Rxctl, r);
1308 static uchar pauseea[] = {1, 0x80, 0xc2, 0, 0, 1};
1311 multicast(void *a, uchar *ea, int on)
1321 r = gmacread(c, Rxctl);
1323 for(ll = &c->mc; *ll != nil; ll = &(*ll)->next)
1324 if(memcmp((*ll)->ea, ea, Eaddrlen) == 0)
1326 *ll = malloc(sizeof **ll);
1327 memmove((*ll)->ea, ea, Eaddrlen);
1329 for(p = nil, l = c->mc; l != nil; p = l, l = l->next)
1330 if(memcmp(l->ea, ea, Eaddrlen) == 0)
1340 memset(f, 0, sizeof f);
1341 if(0 /* flow control */){
1342 b = ethercrc(pauseea, Eaddrlen) & 0x3f;
1343 f[b>>3] |= 1 << (b & 7);
1345 for(l = c->mc; l != nil; l = l->next){
1346 b = ethercrc(l->ea, Eaddrlen) & 0x3f;
1347 f[b>>3] |= 1 << (b & 7);
1349 for(i = 0; i < sizeof f / 2; i++)
1350 gmacwrite(c, Mchash + 2*i, f[i] | f[i+1]<<8);
1351 gmacwrite(c, Rxctl, r | Mfilter);
1354 static int spdtab[4] = {
1365 i = phyread(c, Phyint);
1366 s = phyread(c, Phylstat);
1367 dprint("#l%d: yuk: link %.8ux %.8ux\n", e->ctlrno, i, s);
1369 e->link = (s & Plink) != 0;
1370 if(e->link && c->feat&Ffiber)
1378 dprint("#l%d: yuk: link %d spd %d\n", e->ctlrno, e->link, e->mbps);
1382 txcleanup(Ctlr *c, uint end)
1391 for(rp = r->rp & r->m; rp != end; rp = r->rp & r->m){
1394 if((t->ctl & Eop) == 0)
1397 c->tbring[rp] = nil;
1401 unstarve(&c->txmit);
1405 rx(Ether *e, uint l, uint x, uint flag)
1416 print("#l%d: yuk rx empty\n", e->ctlrno);
1426 cnt = x>>16 & 0x7fff;
1427 if((cnt != l || x&Rxerror) &&
1428 !(c->type == Yukfep && c->rev == 0)){
1429 print("#l%d: yuk rx error %.4ux\n", e->ctlrno, x&0xffff);
1436 unstarve(&c->rxmit);
1440 cksum(Ctlr *c, uint ck, uint css)
1442 if(c->flag & Fnewle && css&(Cisip4|Cisip6) && css&Ctcpok)
1443 return Bipck | Btcpck | Budpck;
1444 else if(ck == 0xffff || ck == 0)
1452 uint i, lim, op, l, x;
1456 static uint ck = Badck;
1460 lim = c->reg16[Stathd] & r->m;
1464 lim = c->reg16[Stathd] & r->m;
1475 ck = getle(s->status, 4) & 0xffff;
1479 x = getle(s->status, 4);
1480 rx(e, l, x, cksum(c, ck, s->ctl));
1485 x = getle(s->status, 4);
1486 txcleanup(c, x & 0xfff);
1488 x = l>>24 & 0xff | l<< 8;
1490 if(x != 0 && c->oport)
1491 txcleanup(c->oport, x);
1494 print("#l%d: yuk: funny opcode %.2ux\n", e->ctlrno, op);
1500 c->reg[Statctl] = Statirqclr;
1509 hwerror(Ether *e, uint cause)
1515 cause = c->reg[Hwe];
1517 print("hwe: no cause\n");
1519 c->reg8[Tgc] = Tgclr;
1522 if(cause & (Hmerr | Hstatus)){
1523 c->reg8[Tstctl1] = Tstwen;
1524 u = pcicfgr16(c->p, PciPSR) | 0x7800;
1525 pcicfgw16(c->p, PciPSR, u);
1526 c->reg8[Tstctl1] = Tstwdis;
1527 cause &= ~(Hmerr | Hstatus);
1530 c->reg8[Tstctl1] = Tstwen;
1531 c->reg[Pciaer + Pciunc>>2] = ~0;
1532 u = c->reg[Pciaer + Pciunc>>2];
1534 print("#l%d: pcierror %.8ux\n", e->ctlrno, u);
1535 c->reg8[Tstctl1] = Tstwdis;
1538 if(cause & Hrxparity){
1539 print("#l%d: ram parity read error. bug? ca %.8ux\n", e->ctlrno, cause);
1540 qrwrite(c, Qtx + Qcsr, Qcirqpar);
1541 cause &= ~Hrxparity;
1543 if(cause & Hrparity){
1544 print("#l%d: ram parity read error. bug? ca %.8ux\n", e->ctlrno, cause);
1545 descriptorfu(e, Qr);
1546 descriptorfu(e, Qtx);
1547 c->reg16[Rictl + c->portno*0x40>>1] = Rirpclr;
1550 if(cause & Hwparity){
1551 print("#l%d: ram parity write error. bug? ca %.8ux\n", e->ctlrno, cause);
1552 descriptorfu(e, Qr);
1553 descriptorfu(e, Qtx);
1554 c->reg16[Rictl + c->portno*0x40>>1] = Riwpclr;
1557 if(cause & Hmfault){
1558 print("#l%d: mac parity error\n", e->ctlrno);
1559 macwrite32(c, Gmfctl, Gmfcpe);
1563 print("#l%d: leftover hwe %.8ux\n", e->ctlrno, cause);
1573 cause = macread8(c, Irq);
1574 cause &= ~(Rxdone | Txdone);
1577 print("#l%d: mac error %.8ux\n", e->ctlrno, cause);
1579 gmacread32(c, Txirq);
1583 gmacread32(c, Rxirq);
1587 macwrite32(c, Gfrxctl, Gmfcfu);
1591 macwrite32(c, Gmfctl, Gmfcfu);
1595 print("#l%d: leftover mac error %.8ux\n", e->ctlrno, cause);
1606 Irx<<Iphy2base, Qr + 0x80, "qr1",
1607 Itxs<<Iphy2base, Qtxs + 0x100, "qtxs1",
1608 Itx<<Iphy2base, Qtx + 0x100, "qtx1",
1612 eerror(Ether *e, uint cause)
1623 if(cause & (Irx | Itxs | Itx)*(1 | 1<<Iphy2base))
1624 for(i = 0; i < nelem(emap); i++){
1625 if((cause & emap[i].i) == 0)
1628 o = prread16(c, q + Pgetidx);
1629 print("#l%d: yuk: bug: %s: @%d ca=%.8ux\n",
1630 e->ctlrno, emap[i].s, o, cause);
1632 qrwrite(c, emap[i].q + Qcsr, Qcirqck);
1633 cause &= ~emap[i].i;
1636 print("#l%d: leftover error %.8ux\n", e->ctlrno, cause);
1652 cause = c->reg[Eisr];
1658 eerror(e, cause & Ierror);
1667 interrupt(Ureg*, void *v)
1676 /* reading Isrc2 masks interrupts */
1677 cause = c->reg[Isrc2];
1678 if(cause == 0 || cause == ~0){
1679 /* reenable interrupts */
1683 unstarve(&c->iproc);
1689 if(c->type == Yukex && c->rev != 1
1690 || c->type == Yukfep
1691 || c->type == Yuksup)
1692 macwrite32(c, Gmfctl, Gmfjon | Gmfsfon);
1694 macwrite32(c, Gmfae, 0x8000 | 0x70); /* tx gmac fifo */
1695 macwrite32(c, Gmfctl, Gmfsfoff);
1704 if(ram = c->reg8[Ramcnt] * 4096/8){ /* in qwords */
1706 rx = ROUNDUP((2*ram)/3, 1024/8);
1707 bufinit(c, Qr, 0, rx);
1708 bufinit(c, Qtx, rx, ram);
1709 rrwrite8(c, Qtxs + Rctl, Rrst); /* sync tx off */
1711 macwrite8(c, Rxplo, 768/8);
1712 macwrite8(c, Rxphi, 1024/8);
1735 snprint(buf, sizeof buf, "#l%dtproc", e->ctlrno);
1736 kproc(buf, tproc, e);
1737 snprint(buf, sizeof buf, "#l%drproc", e->ctlrno);
1738 kproc(buf, rproc, e);
1739 snprint(buf, sizeof buf, "#l%diproc", e->ctlrno);
1740 kproc(buf, iproc, e);
1742 c->reg[Ism] |= Ibmu | Iport<<Iphy2base*c->portno;
1746 ifstat(Ether *e0, void *a, long n, ulong offset)
1754 p = s = malloc(READSTR);
1756 for(i = 0; i < nelem(stattab); i++){
1757 u = gmacread32(c, Stats + stattab[i].offset/4);
1759 p = seprint(p, e, "%s\t%ud\n", stattab[i].name, u);
1761 p = seprint(p, e, "stat %.4ux ctl %.3ux\n", gmacread(c, Stat), gmacread(c, Ctl));
1762 p = seprint(p, e, "pref %.8ux %.4ux\n", prread32(c, Qr + Pctl), prread16(c, Qr + Pgetidx));
1764 p = dumppci(c, p, e);
1765 p = dumpgmac(c, p, e);
1766 p = dumpmac(c, p, e);
1767 p = dumpreg(c, p, e);
1769 seprint(p, e, "%s rev %d phy %s\n", idtab[c->type].name,
1770 c->rev, c->feat&Ffiber? "fiber": "copper");
1771 n = readstr(offset, a, n, s);
1776 static Cmdtab ctltab[] = {
1778 2, "descriptorfu", 1,
1782 ctl(Ether *e, void *buf, long n)
1787 cb = parsecmd(buf, n);
1792 t = lookupcmd(cb, ctltab, nelem(ctltab));
1798 descriptorfu(e, Qr);
1807 yukpcicfgr32(Ctlr *c, uint r)
1809 return c->reg[r + 0x1c00>>2];
1813 yukpcicfgw32(Ctlr *c, uint r, uint v)
1815 c->reg[r + 0x1c00>>2] = v;
1823 u = u0 = yukpcicfgr32(c, Pciphy);
1824 u &= ~phypwr[c->portno];
1825 if(c->type == Yukxl && c->rev > 1)
1826 u |= coma[c->portno];
1828 c->reg8[Tstctl1] = Tstwen;
1829 yukpcicfgw32(c, Pciphy, u);
1830 c->reg8[Tstctl1] = Tstwdis;
1832 if(c->type == Yukfe)
1833 c->reg8[Phyctl] = Aneen;
1834 else if(c->flag & Fapwr)
1835 macwrite32(c, Phy, Gphyrstclr);
1843 if((c->feat & Fnewphy) == 0){
1844 u = phyread(c, Phyextctl);
1845 u &= ~0xf70; /* clear downshift counters */
1846 u |= 0x7<<4; /* mac tx clock = 25mhz */
1847 if(c->type == Yukec)
1848 u |= 2*Dnmstr | Dnslv;
1851 phywrite(c, Phyextctl, u);
1853 u = phyread(c, Phyphy);
1855 /* questionable value */
1856 if(c->feat & Ffiber)
1858 else if(c->feat & Fgbe){
1861 if(c->flag & Fnewphy){
1863 // u |= 2*(1<<12) | 1<<11; /* like 2*Dnmstr | Dnslv */
1864 u |= 2*(1<<9) | 1<<11;
1867 u |= Ppmdixa >> 1; /* why the shift? */
1868 if(c->type == Yukfep && c->rev == 0){
1872 phywrite(c, Phyphy, u);
1873 /* copper/fiber specific stuff gmacwrite(c, Ctl, 0); */
1874 gmacwrite(c, Ctl, 0);
1876 if(c->feat & Ffiber)
1877 phywrite(c, Gbectl, Gbexf | Gbexh);
1879 phywrite(c, Gbectl, Gbef | Gbeh);
1880 phywrite(c, Phyana, Anall);
1881 phywrite(c, Phyctl, Phyrst | Anerst | Aneen);
1882 /* chip specific stuff? */
1883 if (c->type == Yukfep){
1884 u = phyread(c, Phyphy) | Ppnpe;
1885 u &= ~(Ppengy | Ppscrdis);
1886 phywrite(c, Phyphy, u);
1887 // phywrite(c, 0x16, 0x0b54); /* write to fe_led_par */
1889 /* yukfep and rev 0: apply workaround for integrated resistor calibration */
1890 phywrite(c, Phypadr, 17);
1891 phywrite(c, 0x1e, 0x3f60);
1893 phywrite(c, Phyintm, Anok | Anerr | Lsc);
1894 dprint("phyid %.4ux step %.4ux\n", phyread(c, 2), phyread(c, 3));
1902 pcicfgw32(c->p, Pciclk, 0);
1903 c->reg16[Ctst] = Swclr;
1905 c->type = c->reg8[Chip] - 0xb3;
1906 c->rev = c->reg8[Maccfg]>>4 & 0xf;
1909 if(idtab[c->type].okrev != 0xff)
1910 if(c->rev != idtab[c->type].okrev)
1912 c->feat |= idtab[c->type].feat;
1915 if(t == 'L' || t == 'S' || t == 'P')
1918 /* check second port ... whatever */
1923 µ2clk(Ctlr *c, int µs)
1925 return idtab[c->type].mhz * µs;
1929 gmacsetea(Ctlr *c, uint r)
1935 for(i = 0; i < Eaddrlen; i += 2)
1936 gmacwrite(c, r + i, ra[i + 0] | ra[i + 1]<<8);
1947 if(c->type == Yukex)
1948 c->reg16[Asfcs/2] &= ~(Asfbrrst | Asfcpurst | Asfucrst);
1950 c->reg8[Asfcs] = Asfrst;
1951 c->reg16[Ctst] = Asfdis;
1953 c->reg16[Ctst] = Swrst;
1954 c->reg16[Ctst] = Swclr;
1956 c->reg8[Tstctl1] = Tstwen;
1957 pcicfgw16(c->p, PciPSR, pcicfgr16(c->p, PciPSR) | 0xf100);
1958 c->reg16[Ctst] = Mstrclr;
1959 /* fixup pcie extended error goes here */
1961 c->reg8[Pwrctl] = Vauxen | Vccen | Vauxoff | Vccon;
1962 c->reg[Clkctl] = Clkdivdis;
1963 if(c->type == Yukxl && c->rev > 1)
1964 c->reg8[Clkgate] = ~Link2inactive;
1966 c->reg8[Clkgate] = 0;
1967 if(c->flag & Fapwr){
1968 pcicfgw32(c->p, Pciclk, 0);
1969 pcicfgw32(c->p, Pciasp, pcicfgr32(c->p, Pciasp) & Aspmsk);
1970 pcicfgw32(c->p, Pcistate, pcicfgr32(c->p, Pcistate) & Vmain);
1971 pcicfgw32(c->p, Pcicf1, 0);
1972 c->reg[Gpio] |= Norace;
1973 print("yuk2: advanced power %.8ux\n", c->reg[Gpio]);
1975 c->reg8[Tstctl1] = Tstwdis;
1977 for(i = 0; i < c->nports; i++){
1978 macwrite8(c, Linkctl, Linkrst);
1979 macwrite8(c, Linkctl, Linkclr);
1980 if(c->type == Yukex || c->type == Yuksup)
1981 macwrite16(c, Mac, Nomacsec | Nortx);
1984 c->reg[Dpolltm] = Pollstop;
1986 for(i = 0; i < c->nports; i++)
1987 macwrite8(c, Txactl, Txaclr);
1988 for(i = 0; i < c->nports; i++){
1989 c->reg8[i*64 + Rictl] = Riclr;
1990 for(j = 0; j < 12; j++)
1991 c->reg8[i*64 + Rib + j] = 36; /* qword times */
1994 c->reg[Hwem] = Hdflt;
1995 macwrite8(c, Irqm, 0);
1996 for(i = 0; i < 4; i++)
1997 gmacwrite(c, Mchash + 2*i, 0);
1998 gmacwrite(c, Rxctl, Ufilter | Mfilter | Rmcrc);
2000 for(i = 0; i < nelem(c->tbring); i++)
2001 if(b = c->tbring[i]){
2005 for(i = 0; i < nelem(c->rbring); i++)
2006 if(b = c->rbring[i]){
2011 memset(c->tbring, 0, sizeof c->tbring[0] * nelem(c->tbring));
2012 memset(c->rbring, 0, sizeof c->rbring[0] * nelem(c->rbring));
2013 memset(c->tx.r, 0, sizeof c->tx.r[0] * c->tx.cnt);
2014 memset(c->rx.r, 0, sizeof c->rx.r[0] * c->rx.cnt);
2015 memset(c->status.r, 0, sizeof c->status.r[0] * c->status.cnt);
2016 c->reg[Statctl] = Statrst;
2017 c->reg[Statctl] = Statclr;
2018 c->reg[Stataddr + 0] = Pciwaddrl(c->status.r);
2019 c->reg[Stataddr + 4] = Pciwaddrh(c->status.r);
2020 c->reg16[Stattl] = c->status.m;
2021 c->reg16[Statth] = 10;
2022 c->reg8[Statwm] = 16;
2023 if(c->type == Yukxl && c->rev == 0)
2024 c->reg8[Statiwm] = 4;
2026 c->reg8[Statiwm] = 4; //16;
2028 /* set transmit, isr, level timers */
2029 c->reg[Tsti] = µ2clk(c, 1000);
2030 c->reg[Titi] = µ2clk(c, 20);
2031 c->reg[Tlti] = µ2clk(c, 100);
2033 c->reg[Statctl] = Staton;
2035 c->reg8[Tstc] = Tstart;
2036 c->reg8[Tltc] = Tstart;
2037 c->reg8[Titc] = Tstart;
2047 r = macread32(c, Phy) & ~(Gphyrst | Gphyrstclr);
2048 macwrite32(c, Phy, r | Gphyrst);
2049 macwrite32(c, Phy, r | Gphyrstclr);
2050 /* macwrite32(c, Mac, Macrst); ? */
2051 macwrite32(c, Mac, Macrstclr);
2053 if(c->type == Yukxl && c->rev == 0 && c->portno == 1){
2057 macwrite8(c, Irqm, Txurun);
2062 gmacwrite(c, Phyaddr, (r = gmacread(c, Phyaddr)) | Mibclear);
2063 for(i = 0; i < nelem(stattab); i++)
2064 gmacread32(c, Stats + stattab[i].offset/4);
2065 gmacwrite(c, Phyaddr, r);
2067 gmacwrite(c, Txctl, 4<<10); /* collision distance */
2068 gmacwrite(c, Txflow, 0xffff); /* flow control */
2069 gmacwrite(c, Txparm, 3<<14 | 0xb<<9 | 0x1c<<4 | 4);
2070 gmacwrite(c, Rxctl, Ufilter | Mfilter | Rmcrc);
2071 gmacwrite(c, Serctl, 0x04<<11 /* blind */ | Jumboen | 0x1e /* ipig */);
2076 gmacwrite(c, Txmask, 0);
2077 gmacwrite(c, Rxmask, 0);
2078 gmacwrite(c, Trmask, 0);
2080 macwrite32(c, Gfrxctl, Gfrstclr);
2082 if(c->type == Yukex || c->type == Yukfep)
2084 macwrite32(c, Gfrxctl, r);
2085 if(c->type == Yukxl)
2086 macwrite32(c, Grxfm, 0);
2088 macwrite32(c, Grxfm, Ferror);
2089 if(c->type == Yukfep && c->rev == 0)
2090 macwrite32(c, Grxft, 0x178);
2092 macwrite32(c, Grxft, 0xb);
2094 macwrite32(c, Gmfctl, Gmfclr); /* clear reset */
2095 macwrite32(c, Gmfctl, Gmfon); /* on */
2098 if(c->type == Yukfep && c->rev == 0)
2099 c->reg[Gmfea] = c->reg[Gmfea] & ~3;
2106 slice(void **v, uint r, uint sz)
2112 *v = (void*)(a + sz);
2117 setupr(Sring *r, uint cnt)
2133 if(p->mem[0].bar & 1)
2135 c->io = p->mem[0].bar&~0xf;
2136 mem = vmap(c->io, p->mem[0].size);
2138 print("yuk: cant map %llux\n", c->io);
2143 c->reg = (uint*)mem;
2144 c->reg8 = (uchar*)mem;
2145 c->reg16 = (ushort*)mem;
2146 if(memcmp(c->ra, nilea, sizeof c->ra) == 0)
2147 memmove(c->ra, c->reg8 + Macadr + 8*c->portno, Eaddrlen);
2149 setupr(&c->status, Sringcnt);
2150 setupr(&c->tx, Tringcnt);
2151 setupr(&c->rx, Rringcnt);
2153 n = sizeof c->status.r[0] * (c->status.cnt + c->tx.cnt + c->rx.cnt);
2154 n += 16*4096*2; /* rounding slop */
2155 c->alloc = xspanalloc(n, 16*4096, 0); /* unknown alignment constraints */
2156 memset(c->alloc, 0, n);
2159 c->status.r = slice(&v, 16*4096, sizeof c->status.r[0] * c->status.cnt);
2160 c->tx.r = slice(&v, 16*4096, sizeof c->tx.r[0] * c->tx.cnt);
2161 c->rx.r = slice(&v, 16*4096, sizeof c->rx.r[0] * c->rx.cnt);
2163 c->nports = 1; /* BOTCH */
2165 print("yuk: cant reset\n");
2167 vunmap(mem, p->mem[0].size);
2187 vunmap(c->reg, p->mem[0].size);
2199 for(p = nil; p = pcimatch(p, 0, 0); ){
2200 for(i = 0; i < nelem(vtab); i++)
2201 if(vtab[i].vid == p->vid)
2202 if(vtab[i].did == p->did)
2204 if(i == nelem(vtab))
2206 if(nctlr == nelem(ctlrtab)){
2207 print("yuk: too many controllers\n");
2210 c = malloc(sizeof *c);
2212 print("yuk: no memory for Ctlr\n");
2217 c->rbsz = vtab[i].mtu;
2218 ctlrtab[nctlr++] = c;
2234 if(c == nil || c->flag&Fprobe)
2236 if(e->port != 0 && e->port != (ulong)(uintptr)c->reg)
2245 e->irq = c->p->intl;
2246 e->tbdf = c->p->tbdf;
2248 e->maxmtu = c->rbsz;
2249 memmove(e->ea, c->ra, Eaddrlen);
2254 e->multicast = multicast;
2255 e->promiscuous = promiscuous;
2256 e->shutdown = shutdown;
2259 intrenable(e->irq, interrupt, e, e->tbdf, e->name);
2267 addethercard("yuk", pnp);