--- /sys/src/9/pc/etheryuk.c Wed Feb 24 00:00:00 2016
+++ /sys/src/9/pc/etheryuk.c Wed Feb 24 00:00:00 2016
@@ -0,0 +1,2330 @@
+/*
+ * marvell 88e8057 yukon2
+ * copyright © 2009-10 erik quanstrom
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+#include "etherif.h"
+
+#define is64() (sizeof(uintptr) == 8)
+#define dprint(...) if(debug) print(__VA_ARGS__); else {}
+#define Pciwaddrh(va) (sizeof(uintptr)>4? (uvlong)PCIWADDR(va)>>32: 0)
+#define Pciwaddrl(va) PCIWADDR(va)
+
+enum {
+ Nctlr = 4,
+ Nrb = 1024,
+ Rbalign = 64,
+ Fprobe = 1<<0,
+ Sringcnt = 2048,
+ Tringcnt = 512,
+// Rringcnt = Nrb,
+ Rringcnt = 512,
+};
+
+enum {
+ /* pci registers */
+ Pciphy = 0x40,
+ Pciclk = 0x80,
+ Pciasp = 0x84,
+ Pcistate = 0x88,
+ Pcicf0 = 0x90,
+ Pcicf1 = 0x94,
+
+ /* “csr” registers */
+ Ctst = 0x0004/2, /* control and status */
+ Pwrctl = 0x0007, /* power control */
+ Isr = 0x0008/4, /* interrupt src */
+ Ism = 0x000c/4, /* interrupt mask */
+ Hwe = 0x0010/4, /* hw error */
+ Hwem = 0x0014/4, /* hw error mask*/
+ Isrc2 = 0x001c/4,
+ Eisr = 0x0024/4,
+ Lisr = 0x0028/4, /* leave isr */
+ Macadr = 0x0100, /* mac address 2ports*3 */
+ Pmd = 0x0119,
+ Maccfg = 0x011a,
+ Chip = 0x011b,
+ Ramcnt = 0x011c, /* # of 4k blocks */
+ Hres = 0x011e,
+ Clkgate = 0x011d,
+ Clkctl = 0x0120/4,
+ Tstctl1 = 0x0158,
+ Tstctl2 = 0x0159,
+ Gpio = 0x015c/4,
+
+ Rictl = 0x01a0, /* ri ram buffer ctl */
+ Rib = 0x0190, /* ri buffer0 */
+
+ /* other unoffset registers */
+ Asfcs = 0x0e68, /* asf command and status */
+ Asfhost = 0x0e6c/4,
+
+ Statctl = 0x0e80/4, /* status */
+ Stattl = 0x0e84/2, /* tail (previous) status addr */
+ Stataddr = 0x0e88/4, /* status address low */
+ Statth = 0x0e98/2,
+ Stathd = 0x0e9c/2,
+ Statwm = 0x0eac, /* stat watermark */
+ Statiwm = 0x0ead, /* isr stat watermark */
+
+ Dpolltm = 0x0e08/4, /* descriptor pool timer */
+
+ /* timers */
+ Tgv = 0x0e14/4, /* gmac timer current value */
+ Tgc = 0x0e18, /* gmac timer ctl */
+ Tgt = 0x0e1a, /* gmac timer test */
+
+ Tsti = 0x0ec0/4, /* stat tx timer ini */
+ Tlti = 0x0eb0/4, /* level */
+ Titi = 0x0ed0/4, /* isr */
+
+ Tstc = 0x0ec8, /* stat tx timer ctl */
+ Tltc = 0x0eb8, /* level timer ctl */
+ Titc = 0x0ed8, /* isr timer ctl */
+
+ /* “gmac” registers */
+ Stat = 0x000/2,
+ Ctl = 0x004/2,
+ Txctl = 0x008/2,
+ Rxctl = 0x00c/2,
+ Txflow = 0x010/2,
+ Txparm = 0x014/2,
+ Serctl = 0x018/2, /* serial mode */
+ Mchash = 0x034/2, /* 4 registers; 4 bytes apart */
+
+ /* interrupt sources and masks */
+ Txirq = 0x044/2,
+ Rxirq = 0x048/2,
+ Trirq = 0x04c/2, /* tx/rx overflow irq source */
+ Txmask = 0x050/2,
+ Rxmask = 0x054/2,
+ Trmask = 0x058/2,
+
+ Smictl = 0x080/2, /* serial mode control */
+ Smidata = 0x084/2,
+ Phyaddr = 0x088/2,
+
+ Ea0 = 0x01c/2, /* 3 16 bit gmac registers */
+ Ea1 = 0x028/2,
+
+ Stats = 0x0100/4,
+
+ /* mac registers */
+ Txactl = 0x210, /* transmit arbiter ctl */
+
+ Grxea = 0x0c40/4, /* rx fifo end address */
+ Gfrxctl = 0x0c48/4, /* gmac rxfifo ctl */
+ Grxfm = 0x0c4c/4, /* fifo flush mask */
+ Grxft = 0x0c50/4, /* fifo flush threshold */
+ Grxtt = 0x0c54/4, /* rx truncation threshold */
+ Gmfea = 0x0d40/4, /* end address */
+ Gmfae = 0x0d44/4, /* almost empty thresh */
+ Gmfctl = 0x0d48/4, /* tx gmac fifo ctl */
+
+ Rxphi = 0x0c58, /* pause high watermark */
+ Rxplo = 0x0c5c, /* pause low watermark */
+
+ Rxwp = 0x0c60/4,
+ Rxwlev = 0x0c68/4,
+ Rxrp = 0x0c70/4,
+ Rxrlev = 0x0c78/4,
+
+ Mac = 0x0f00/4, /* global mac control */
+ Phy = 0x0f04/4, /* phy control register */
+
+ Irq = 0x0f08, /* irq source */
+ Irqm = 0x0f0c, /* irq mask */
+ Linkctl = 0x0f10,
+
+ /* queue registers; all offsets from Qbase*/
+ Qbase = 0x0400,
+ Qportsz = 0x0080, /* BOTCH; tx diff is 2x rx diff */
+
+ Qr = 0x000,
+ Qtxs = 0x200,
+ Qtx = 0x280,
+
+ /* queue offsets */
+ Qd = 0x00,
+ Qvlan = 0x20,
+ Qdone = 0x24,
+ Qaddrl = 0x28,
+ Qaddrh = 0x2c,
+ Qbc = 0x30,
+ Qcsr = 0x34, /* 32bit */
+ Qtest = 0x38,
+ Qwm = 0x40,
+
+ /* buffer registers; all offsets from Rbase */
+ Rbase = 0x0800,
+
+ Rstart = 0x00,
+ Rend = 0x04,
+ Rwp = 0x08,
+ Rrp = 0x0c,
+ Rpon = 0x10, /* pause frames on */
+ Rpoff = 0x14, /* pause frames off */
+ Rhon = 0x18, /* high-priority frames on */
+ Rhoff = 0x1c, /* high-priority frames off */
+ Rctl = 0x28,
+
+ /* prefetch */
+ Pbase = 0x450,
+ Pctl = 0x00,
+ Plidx = 0x04, /* last addr; 16 bit */
+ Paddrl = 0x08,
+ Paddrh = 0x0c,
+ Pgetidx = 0x10, /* 16 bit */
+ Pputidx = 0x14, /* 16 bit */
+ Pfifow = 0x20, /* 8 bit */
+ Pfifor = 0x24, /* 8 bit */
+ Pfifowm = 0x20, /* 8 bit */
+
+ /* indirect phy registers */
+ Phyctl = 0x000,
+ Phystat = 0x001,
+ Phyid0 = 0x002,
+ Phyid1 = 0x003,
+ Phyana = 0x004, /* auto neg advertisement */
+ Phylpa = 0x005, /* link partner ability */
+ Phyanee = 0x006, /* auto neg adv expansion */
+ Phynp = 0x007, /* next page */
+ Phylnp = 0x008, /* link partner next page */
+ Gbectl = 0x009,
+ Gbestat = 0x00a,
+ Phyphy = 0x010, /* phy specific ctl */
+ Phylstat = 0x011,
+ Phyintm = 0x012, /* phy interrupt mask */
+ Phyint = 0x013,
+ Phyextctl = 0x014,
+ Phyrxe = 0x015, /* rx error counter */
+ Phypage = 0x016, /* external address */
+ Phypadr = 0x01d, /* phy page address */
+};
+
+enum {
+ /* Pciasp */
+ Aspforce = 1<<15,
+ Aspglinkdn = 1<<14, /* gphy link down */
+ Aspfempty = 1<<13,
+ Aspclkrun = 1<<12,
+ Aspmsk = Aspforce | Aspglinkdn | Aspfempty | Aspclkrun,
+
+ /* Pcistate */
+ Vmain = 3<<27,
+
+ /* Stat */
+ Sfast = 1<<15, /* 100mbit */
+ Duplex = 1<<14,
+ Txnofc = 1<<13, /* tx flow control disabled */
+ Link = 1<<12, /* link up */
+ Pausest = 1<<11, /* pause state */
+ Txactive = 1<<10,
+ Excesscol = 1<<9,
+ Latecol = 1<<8,
+ Physc = 1<<5, /* phy status change */
+ Sgbe = 1<<4, /* gbe speed */
+ Rxnofc = 1<<2, /* rx flow control disabled */
+ Promisc = 1<<1, /* promiscuous mode enabled */
+
+ /* Ctl */
+ Promiscen = 1<<14,
+ Txfcdis = 1<<13,
+ Txen = 1<<12,
+ Rxen = 1<<11,
+ Bursten = 1<<10,
+ Loopen = 1<<9,
+ Gbeen = 1<<7,
+ Fpass = 1<<6, /* "force link pass" ? */
+ Duplexen = 1<<5,
+ Rxfcdis = 1<<4,
+ Fasten = 1<<3, /* enable 100mbit */
+ Adudis = 1<<2, /* disable auto upd duplex */
+ Afcdis = 1<<1, /* disable auto upd flow ctl */
+ Aspddis = 1<<0, /* disable auto upd speed */
+
+ /* Rxctl */
+ Ufilter = 1<<15, /* unicast filter */
+ Mfilter = 1<<14, /* multicast filter */
+ Rmcrc = 1<<13, /* remove frame crc */
+
+ /* Serctl */
+ Vlanen = 1<<9,
+ Jumboen = 1<<8,
+
+ /* Txactl */
+ Txaclr = 1<<1,
+ Txarst = 1<<0,
+
+ /* Asfcs: yukex only */
+ Asfbrrst = 1<<9, /* bridge reset */
+ Asfcpurst = 1<<8, /* cpu reset */
+ Asfucrst = 3<<0, /* µctlr reset */
+
+ /* Asfcs */
+ Asfhvos = 1<<4, /* os present */
+ Asfrst = 1<<3,
+ Asfrun = 1<<2,
+ Asfcirq = 1<<1,
+ Afsirq = 1<<0,
+
+ /* Statctl */
+ Statirqclr = 1<<4,
+ Staton = 1<<3,
+ Statoff = 1<<2,
+ Statclr = 1<<1,
+ Statrst = 1<<0,
+
+ /* Mac */
+ Nomacsec = 1<<13 | 1<<11,
+ Nortx = 1<<9,
+ Macpause = 1<<3,
+ Macpauseoff = 1<<2,
+ Macrstclr = 1<<1,
+ Macrst = 1<<0,
+
+ /* Phy */
+ Gphyrstclr = 1<<1,
+ Gphyrst = 1<<0,
+
+ /* Irqm */
+ Txovfl = 1<<5, /* tx counter overflow */
+ Rxovfl = 1<<4, /* rx counter overflow */
+ Txurun = 1<<3, /* transmit fifo underrun */
+ Txdone = 1<<2, /* frame tx done */
+ Rxorun = 1<<1, /* rx fifo overrun */
+ Rxdone = 1<<0, /* frame rx done */
+
+ /* Linkctl */
+ Linkclr = 1<<1,
+ Linkrst = 1<<0,
+
+ /* Smictl */
+ Smiread = 1<<5,
+ Smiwrite = 0<<5,
+ Smirdone = 1<<4,
+ Smibusy = 1<<3,
+
+ /* Phyaddr */
+ Mibclear = 1<<5,
+
+ /* Ctst */
+ Asfdis = 1<<12, /* asf disable */
+ Clken = 1<<11, /* enable clock */
+
+ Swirq = 1<<7,
+ Swirqclr = 1<<6,
+ Mstopped = 1<<5, /* master is stopped */
+ Mstop = 1<<4, /* stop master */
+ Mstrclr = 1<<3, /* master reset clear */
+ Mstrrset = 1<<2, /* master reset */
+ Swclr = 1<<1,
+ Swrst = 1<<0,
+
+ /* Pwrctl */
+ Vauxen = 1<<7,
+ Vauxdis = 1<<6,
+ Vccen = 1<<5,
+ Vccdis = 1<<4,
+ Vauxon = 1<<3,
+ Vauxoff = 1<<2,
+ Vccon = 1<<1,
+ Vccoff = 1<<0,
+
+ /* timers */
+ Tstart = 1<<2,
+ Tstop = 1<<1,
+ Tclrirq = 1<<0,
+
+ /* Dpolltm */
+ Pollstart = 1<<1,
+ Pollstop = 1<<0,
+
+ /* csr interrupts: Isrc2, Eisr, etc. */
+ Ihwerr = 1<<31,
+ Ibmu = 1<<30, /* sring irq */
+ Isoftware = 1<<25,
+
+ Iphy = 1<<4,
+ Imac = 1<<3,
+ Irx = 1<<2,
+ Itxs = 1<<1, /* descriptor error */
+ Itx = 1<<0, /* descriptor error */
+
+ Iport = 0x1f,
+ Iphy2base = 8,
+ Ierror = (Imac | Itx | Irx)*(1 | 1<<Iphy2base),
+
+ /* hwe interrupts: Hwe Hwem */
+ Htsof = 1<<29, /* timer stamp overflow */
+ Hsensor = 1<<28,
+ Hmerr = 1<<27, /* master error */
+ Hstatus = 1<<26, /* status exception */
+ Hpcie = 1<<25, /* pcie error */
+ Hpcie2 = 1<<24, /* " */
+
+ Hrparity = 1<<5, /* ram read parity error */
+ Hwparity = 1<<4, /* ram write parity error */
+ Hmfault = 1<<3, /* mac fault */
+ Hrxparity = 1<<2, /* rx parity */
+ Htcptxs = 1<<1, /* tcp length mismatch */
+ Htcptxa = 1<<0, /* tcp length mismatch */
+
+ H1base = 1<<0,
+ H2base = 1<<8,
+ Hmask = 0x3f,
+ Hdflt = Htsof | Hmerr | Hstatus | Hmask*(H1base | H2base),
+
+ /* Clkctl */
+ Clkdiven = 1<<1,
+ Clkdivdis = 1<<0,
+
+ /* Clkgate */
+ Link2inactive = 1<<7,
+
+ /* Phyctl */
+ Phyrst = 1<<15,
+ Phy100 = 1<<14, /* manual enable 100mbit */
+ Aneen = 1<<12, /* auto negotiation enable */
+ Phyoff = 1<<11, /* turn phy off */
+ Anerst = 1<<9, /* auto neg reset */
+ Phydpx = 1<<8,
+ Phy1000 = 1<<5, /* manual enable gbe */
+
+ /* Phyana */
+ Annp = 1<<15, /* request next page */
+ Anack = 1<<14, /* ack rx (read only) */
+ Anrf = 1<<13, /* remote fault */
+ Anpa = 1<<11, /* try asymmetric pause */
+ Anp = 1<<10, /* try pause */
+ An100f = 1<<8,
+ An100h = 1<<7,
+ An10f = 1<<6,
+ An10h = 1<<5,
+ Anonly = 1<<0,
+ Anall = An100f | An100h | An10f | An10h | Anonly,
+
+ /* Gbectl */
+ Gbef = 1<<9, /* auto neg gbe full */
+ Gbeh = 1<<8, /* auto neg gbe half */
+ Gbexf = 1<<6, /* auto neg gbe full fiber */
+ Gbexh = 1<<5, /* auto neg gbe full fiber */
+
+ /* Phyphy */
+ Pptf = 3<<14, /* tx fifo depth */
+ Pprf = 3<<12, /* rx fifo depth */
+ Pped = 3<<8, /* energy detect */
+ Ppmdix = 3<<5, /* mdix conf */
+ Ppmdixa = 3<<5, /* automdix */
+
+ Ppengy = 1<<14, /* fe+ enable energy detect */
+ Ppscrdis = 1<<9, /* fe+ scrambler disable */
+ Ppnpe = 1<<12, /* fe+ enable next page */
+
+ /* Phylstat */
+ Physpd = 3<<14,
+ Phydupx = 1<<13,
+ Phypr = 1<<12, /* page rx */
+ Phydone = 1<<11, /* speed and duplex neg. done */
+ Plink = 1<<10,
+ Pwirelen = 7<<7,
+ Pmdi = 1<<6,
+ Pdwnsh = 1<<5, /* downshift */
+ Penergy = 1<<4, /* energy detect */
+ Ptxpause = 1<<3, /* tx pause enabled */
+ Prxpause = 1<<2, /* rx pause enabled */
+ Ppol = 1<<2, /* polarity */
+ Pjarjar = 1<<1, /* mesa no understasa */
+
+ /* Phyintm */
+ Anerr = 1<<15, /* an error */
+ Lsp = 1<<14, /* link speed change */
+ Andc = 1<<13, /* an duplex change */
+ Anok = 1<<11,
+ Lsc = 1<<10, /* link status change */
+ Symerr = 1<<9, /* symbol error */
+ Fcarr = 1<<8, /* false carrier */
+ Fifoerr = 1<<7,
+ Mdich = 1<<6,
+ Downsh = 1<<5,
+ Engych = 1<<4, /* energy change */
+ Dtech = 1<<2, /* dte power det status */
+ Polch = 1<<1, /* polarity change */
+ Jabber = 1<<0,
+
+ /* Phyextctl */
+ Dnmstr = 1<<9, /* master downshift; 0: 1x; 1: 2x; 2: 3x */
+ Dnslv = 1<<8,
+
+ /* Tgc */
+ Tgstart = 1<<2,
+ Tgstop = 1<<1,
+ Tgclr = 1<<0, /* clear irq */
+
+ /* Tstctl1 */
+ Tstwen = 1<<1, /* enable config reg r/w */
+ Tstwdis = 1<<0, /* disable config reg r/w */
+
+ /* Gpio */
+ Norace = 1<<13,
+
+ /* Rictl */
+ Rirpclr = 1<<9,
+ Riwpclr = 1<<8,
+ Riclr = 1<<1,
+ Rirst = 1<<0,
+
+ /* Rbase opcodes */
+ Rsfon = 1<<5, /* enable store/fwd */
+ Rsfoff = 1<<4,
+ Renable = 1<<3,
+ Rdisable = 1<<2,
+ Rrstclr = 1<<1,
+ Rrst = 1<<0,
+
+ /* Qbase opcodes */
+ Qidle = 1<<31,
+ Qtcprx = 1<<30,
+ Qiprx = 1<<29,
+ Qrssen = 1<<15,
+ Qrssdis = 1<<14,
+ Qsumen = 1<<13, /* tcp/ip cksum */
+ Qsumdis = 1<<12,
+ Qcirqpar = 1<<11, /* clear irq on parity errors */
+ Qcirqck = 1<<10,
+ Qstop = 1<<9,
+ Qstart = 1<<8,
+ Qfifoon = 1<<7,
+ Qfifooff = 1<<6,
+ Qfifoen = 1<<5,
+ Qfiforst = 1<<4,
+ Qenable = 1<<3,
+ Qdisable = 1<<2,
+ Qrstclr = 1<<1,
+ Qrst = 1<<0,
+
+ Qallclr = Qfiforst | Qfifooff | Qrstclr,
+ Qgo = Qcirqpar | Qcirqck | Qstart | Qfifoen | Qenable,
+
+ /* Qtest bits */
+ Qckoff = 1<<31, /* tx: auto checksum off */
+ Qckon = 1<<30,
+ Qramdis = 1<<24, /* rx: ram disable */
+
+ /* Pbase opcodes */
+ Prefon = 1<<3, /* prefetch on */
+ Prefoff = 1<<2,
+ Prefrstclr = 1<<1,
+ Prefrst = 1<<0,
+
+ /* ring opcodes */
+ Hw = 0x80, /* bitmask */
+ Ock = 0x12, /* tcp checksum start */
+ Oaddr64 = 0x21,
+ Obuf = 0x40,
+ Opkt = 0x41,
+ Orxstat = 0x60,
+ Orxts = 0x61, /* rx timestamp */
+ Orxvlan = 0x62,
+ Orxchks = 0x64,
+ Otxidx = 0x68,
+ Omacs = 0x6c, /* macsec */
+ Oputidx = 0x70,
+
+ /* ring status */
+ Eop = 0x80,
+
+ /* Gfrxctl */
+ Gftrunc = 1<<27,
+ Gftroff = 1<<26,
+
+ Gfroon = 1<<19, /* flush on rx overrun */
+ Gfrooff = 1<<18,
+ Gffon = 1<<7, /* rx fifo flush mode on */
+ Gffoff = 1<<6,
+ Gfon = 1<<3,
+ Gfoff = 1<<2,
+ Gfrstclr = 1<<1,
+ Gfrst = 1<<0,
+
+ /* Gmfctl */
+ Gmfsfoff = 1<<31, /* disable store-forward (ec ultra) */
+ Gmfsfon = 1<<30, /* able store-forward (ec ultra) */
+ Gmfvon = 1<<25, /* vlan tag on */
+ Gmfvoff = 1<<24, /* vlan off */
+ Gmfjon = 1<<23, /* jumbo on (ec ultra) */
+ Gmfjoff = 1<<22, /* jumbo off */
+ Gmfcfu = 1<<6, /* clear fifio underrun irq */
+ Gmfcfc = 1<<5, /* clear frame complete irq */
+ Gmfcpe = 1<<4, /* clear parity error irq */
+ Gmfon = 1<<3,
+ Gmfoff = 1<<2,
+ Gmfclr = 1<<1,
+ Gmfrst = 1<<0,
+
+ /* rx frame */
+ Flen = 0x7fff<<17,
+ Fvlan = 1<<13,
+ Fjabbr = 1<<12,
+ Ftoosm = 1<<11,
+ Fmc = 1<<10, /* multicast */
+ Fbc = 1<<9,
+ Fok = 1<<8, /* good frame */
+ Fokfc = 1<<7,
+ Fbadfc = 1<<6,
+ Fmiierr = 1<<5,
+ Ftoobg = 1<<4, /* oversized */
+ Ffrag = 1<<3, /* fragment */
+ Fcrcerr = 1<<1,
+ Ffifoof = 1<<0, /* fifo overflow */
+ Ferror = Ffifoof | Fcrcerr | Ffrag | Ftoobg
+ | Fmiierr | Fbadfc | Ftoosm | Fjabbr,
+
+ /* rx checksum bits in Status.ctl */
+ Badck = 5, /* arbitrary bad checksum */
+
+ Ctcpok = 1<<7, /* tcp or udp cksum ok */
+ Cisip6 = 1<<3,
+ Cisip4 = 1<<1,
+
+ /* more status ring rx bits */
+ Rxvlan = 1<<13,
+ Rxjab = 1<<12, /* jabber */
+ Rxsmall = 1<<11, /* too small */
+ Rxmc = 1<<10, /* multicast */
+ Rxbc = 1<<9, /* bcast */
+ Rxok = 1<<8,
+ Rxfcok = 1<<7, /* flow control pkt */
+ Rxfcbad = 1<<6,
+ Rxmiierr = 1<<5,
+ Rxbig = 1<<4, /* too big */
+ Rxfrag = 1<<3,
+ Rxcrcerr = 1<<1,
+ Rxfov = 1<<0, /* fifo overflow */
+ Rxerror = Rxfov | Rxcrcerr | Rxfrag | Rxbig | Rxmiierr
+ | Rxfcbad | Rxsmall | Rxjab,
+};
+
+enum {
+ Ffiber = 1<<0,
+ Fgbe = 1<<1,
+ Fnewphy = 1<<2,
+ Fapwr = 1<<3,
+ Fnewle = 1<<4,
+ Fram = 1<<5,
+ Fancy =Fgbe | Fnewphy | Fapwr,
+
+ Yukxl = 0,
+ Yukecu,
+ Yukex,
+ Yukec,
+ Yukfe,
+ Yukfep,
+ Yuksup,
+ Yukul2,
+ Yukba, /* doesn't exist */
+ Yukopt,
+ Nyuk,
+};
+
+typedef struct Chipid Chipid;
+typedef struct Ctlr Ctlr;
+typedef void (*Freefn)(Block*);
+typedef struct Kproc Kproc;
+typedef struct Mc Mc;
+typedef struct Stattab Stattab;
+typedef struct Status Status;
+typedef struct Sring Sring;
+typedef struct Vtab Vtab;
+
+struct Chipid {
+ uchar feat;
+ uchar okrev;
+ uchar mhz;
+ char *name;
+};
+
+struct Kproc {
+ Rendez;
+ uint event;
+};
+
+struct Sring {
+ uint wp;
+ uint rp;
+ uint cnt;
+ uint m;
+ Status *r;
+};
+
+struct Ctlr {
+ Pcidev *p;
+ Ctlr *oport; /* port 2 */
+ uchar qno;
+ uchar attach;
+ uchar rxinit;
+ uchar txinit;
+ uchar flag;
+ uchar feat;
+ uchar type;
+ uchar rev;
+ uchar nports;
+ uchar portno;
+ uintptr io;
+ uchar *reg8;
+ u16int *reg16;
+ u32int *reg;
+ uint rbsz;
+ uchar ra[Eaddrlen];
+ uint mca;
+ uint nmc;
+ Mc *mc;
+ void *alloc;
+ Sring status;
+ Sring tx;
+ Block *tbring[Tringcnt];
+ Sring rx;
+ Block *rbring[Rringcnt];
+ Kproc txmit;
+ Kproc rxmit;
+ Kproc iproc;
+};
+
+struct Mc {
+ Mc *next;
+ uchar ea[Eaddrlen];
+};
+
+struct Stattab {
+ uint offset;
+ char *name;
+};
+
+struct Status {
+ uchar status[4];
+ uchar l[2];
+ uchar ctl;
+ uchar op;
+};
+
+struct Vtab {
+ int vid;
+ int did;
+ int mtu;
+ char *name;
+};
+
+static Chipid idtab[] = {
+[Yukxl] Fgbe | Fnewphy, 0xff, 156, "yukon-2 xl",
+[Yukecu] Fancy, 0xff, 125, "yukon-2 ec ultra",
+[Yukex] Fancy | Fnewle, 0xff, 125, "yukon-2 extreme",
+[Yukec] Fgbe, 2, 125, "yukon-2 ec",
+[Yukfe] 0, 0xff, 100, "yukon-2 fe",
+[Yukfep] Fnewphy|Fapwr | Fnewle, 0xff, 50, "yukon-2 fe+",
+[Yuksup] Fgbe | Fnewphy | Fnewle, 0xff, 125, "yukon-2 supreme",
+[Yukul2] Fgbe |Fapwr, 0xff, 125, "yukon-2 ultra2",
+[Yukba] 0, 0, 0, "??",
+[Yukopt] Fancy, 0xff, 125, "yukon-2 optima",
+};
+
+static Vtab vtab[] = {
+ 0x11ab, 0x4354, 1514, "88e8040", /* unsure on mtu */
+ 0x11ab, 0x4362, 1514, "88e8053",
+ 0x11ab, 0x4364, 1514, "88e8056",
+ 0x11ab, 0x4380, 1514, "88e8057",
+ 0x11ab, 0x436b, 1514, "88e8071", /* unsure on mtu */
+ 0x1186, 0x4b00, 9000, "dge-560t",
+ 0x1186, 0x4b02, 1514, "dge-550sx",
+ 0x1186, 0x4b03, 1514, "dge-550t",
+};
+
+static Stattab stattab[] = {
+ 0, "rx ucast",
+ 8, "rx bcast",
+ 16, "rx pause",
+ 24, "rx mcast",
+ 32, "rx chk seq",
+
+ 48, "rx ok low",
+ 56, "rx ok high",
+ 64, "rx bad low",
+ 72, "rx bad high",
+
+ 80, "rx frames < 64",
+ 88, "rx frames < 64 fcs",
+ 96, "rx frames 64",
+ 104, "rx frames 65-127",
+ 112, "rx frames 128-255",
+ 120, "rx frames 256-511",
+ 128, "rx frames 512-1023",
+ 136, "rx frames 1024-1518",
+ 144, "rx frames 1519-mtu",
+ 152, "rx frames too long",
+ 160, "rx jabber",
+ 176, "rx fifo oflow",
+
+ 192, "tx ucast",
+ 200, "tx bcast",
+ 208, "tx pause",
+ 216, "tx mcast",
+
+ 224, "tx ok low",
+ 232, "tx ok hi",
+
+ 240, "tx frames 64",
+ 248, "tx frames 65-127",
+ 256, "tx frames 128-255",
+ 264, "tx frames 256-511",
+ 272, "tx frames 512-1023",
+ 280, "tx frames 1024-1518",
+ 288, "tx frames 1519-mtu",
+
+ 304, "tx coll",
+ 312, "tx late coll",
+ 320, "tx excess coll",
+ 328, "tx mul col",
+ 336, "tx single col",
+ 344, "tx underrun",
+};
+
+static uint phypwr[] = {1<<26, 1<<27};
+static uint coma[] = {1<<28, 1<<29};
+static uchar nilea[Eaddrlen];
+static int debug;
+static Ctlr *ctlrtab[Nctlr];
+static int nctlr;
+static struct {
+ union {
+ struct {
+ Lock;
+ Block *b;
+ uint starve;
+ };
+ uchar pad[128]; /* cacheline */
+ };
+ Kproc *k;
+ Block *x;
+ uint nfast;
+ uint nslow;
+} rbtab[Nctlr];
+
+static int
+icansleep(void *v)
+{
+ Kproc *k;
+
+ k = v;
+ return k->event != 0;
+}
+
+static void
+unstarve(Kproc *k)
+{
+ k->event = 1;
+ wakeup(k);
+}
+
+static void
+starve(Kproc *k)
+{
+ sleep(k, icansleep, k);
+ k->event = 0;
+}
+
+static Status*
+getslot(Sring *r, Kproc *k)
+{
+ if(r->rp + r->m - r->wp & ~r->m)
+ starve(k);
+ return r->r + (r->wp++ & r->m);
+}
+
+static int
+getnslot(Sring *r, uint *wp, Status **t, uint n)
+{
+ int i;
+
+ if(r->rp + r->m - (n - 1) - wp[0] & ~r->m)
+ return -1;
+ for(i = 0; i < n; i++)
+ t[i] = r->r + (wp[0]++ & r->m);
+ return 0;
+}
+
+/* assume allocs come from a single thread; 30*0.999x speedup */
+static Block*
+rballoc(int t)
+{
+ Block *b;
+
+ if((b = rbtab[t].x) != nil){
+ rbtab[t].nfast++;
+ rbtab[t].x = b->next;
+ b->next = nil;
+ return b;
+ }
+
+ ilock(&rbtab[t]);
+ b = rbtab[t].x = rbtab[t].b;
+ rbtab[t].b = nil;
+ if(b == nil)
+ rbtab[t].starve = 1;
+ iunlock(&rbtab[t]);
+
+ rbtab[t].nslow++;
+ if(b != nil){
+ rbtab[t].x = b->next;
+ b->next = nil;
+ }
+ return b;
+}
+
+static void
+rbfree(Block *b, int t)
+{
+ b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, Rbalign);
+ b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
+ ilock(&rbtab[t]);
+ b->next = rbtab[t].b;
+ if(b->next == nil && rbtab[t].starve){
+ rbtab[t].starve = 0;
+ unstarve(rbtab[t].k);
+ }
+ rbtab[t].b = b;
+ iunlock(&rbtab[t]);
+}
+
+static void
+rbfree0(Block *b)
+{
+ rbfree(b, 0);
+}
+
+static void
+rbfree1(Block *b)
+{
+ rbfree(b, 1);
+}
+
+static void
+rbfree2(Block *b)
+{
+ rbfree(b, 2);
+}
+
+static void
+rbfree3(Block *b)
+{
+ rbfree(b, 3);
+}
+
+static Freefn freetab[Nctlr] = {
+ rbfree0,
+ rbfree1,
+ rbfree2,
+ rbfree3,
+};
+
+static uint
+macread32(Ctlr *c, uint r)
+{
+ return c->reg[c->portno*0x20 + r];
+}
+
+static void
+macwrite32(Ctlr *c, uint r, uint v)
+{
+ c->reg[c->portno*0x20 + r] = v;
+}
+
+static uint
+macread16(Ctlr *c, uint r)
+{
+ return c->reg16[c->portno*0x40 + r];
+}
+
+static void
+macwrite16(Ctlr *c, uint r, uint v)
+{
+ c->reg16[c->portno*0x40 + r] = v;
+}
+
+static uint
+macread8(Ctlr *c, uint r)
+{
+ return c->reg8[c->portno*0x80 + r];
+}
+
+static void
+macwrite8(Ctlr *c, uint r, uint v)
+{
+ c->reg8[c->portno*0x80 + r] = v;
+}
+
+static uint gmac32[2] = {
+ 0x2800/4,
+ 0x3800/4,
+};
+
+static ushort
+gmacread32(Ctlr *c, uint r)
+{
+ return c->reg[gmac32[c->portno] + r];
+}
+
+static void
+gmacwrite32(Ctlr *c, uint r, uint v)
+{
+ c->reg[gmac32[c->portno] + r] = v;
+}
+
+static uint gmac[2] = {
+ 0x2800/2,
+ 0x3800/2,
+};
+
+static ushort
+gmacread(Ctlr *c, uint r)
+{
+ return c->reg16[gmac[c->portno] + r];
+}
+
+static void
+gmacwrite(Ctlr *c, uint r, ushort v)
+{
+ c->reg16[gmac[c->portno] + r] = v;
+}
+
+static uint
+qrread(Ctlr *c, uint r)
+{
+ return c->reg[Qbase + c->portno*Qportsz + r>>2];
+}
+
+static void
+qrwrite(Ctlr *c, uint r, uint v)
+{
+ c->reg[Qbase + c->portno*Qportsz + r>>2] = v;
+}
+
+static uint
+qrread16(Ctlr *c, uint r)
+{
+ return c->reg16[Qbase + c->portno*Qportsz + r>>1];
+}
+
+static void
+qrwrite16(Ctlr *c, uint r, uint v)
+{
+ c->reg16[Qbase + c->portno*Qportsz + r>>1] = v;
+}
+
+static uint
+qrread8(Ctlr *c, uint r)
+{
+ return c->reg8[Qbase + c->portno*Qportsz + r>>0];
+}
+
+static void
+qrwrite8(Ctlr *c, uint r, uint v)
+{
+ c->reg8[Qbase + c->portno*Qportsz + r>>0] = v;
+}
+
+static uint
+rrread32(Ctlr *c, uint r)
+{
+ return c->reg[Rbase + c->portno*Qportsz + r>>2];
+}
+
+static void
+rrwrite32(Ctlr *c, uint r, uint v)
+{
+ c->reg[Rbase + c->portno*Qportsz + r>>2] = v;
+}
+
+static void
+rrwrite8(Ctlr *c, uint r, uint v)
+{
+ c->reg8[Rbase + c->portno*Qportsz + r] = v;
+}
+
+static uint
+rrread8(Ctlr *c, uint r)
+{
+ return c->reg8[Rbase + c->portno*Qportsz + r];
+}
+
+static uint
+prread32(Ctlr *c, uint r)
+{
+ return c->reg[Pbase + c->portno*Qportsz + r>>2];
+}
+
+static void
+prwrite32(Ctlr *c, uint r, uint v)
+{
+ c->reg[Pbase + c->portno*Qportsz + r>>2] = v;
+}
+
+static uint
+prread16(Ctlr *c, uint r)
+{
+ return c->reg16[Pbase + c->portno*Qportsz + r>>1];
+}
+
+static void
+prwrite16(Ctlr *c, uint r, uint v)
+{
+ c->reg16[Pbase + c->portno*Qportsz + r>>1] = v;
+}
+
+static ushort
+phyread(Ctlr *c, uint r)
+{
+ ushort v;
+
+ gmacwrite(c, Smictl, Smiread | r<<6);
+ for(;;){
+ v = gmacread(c, Smictl);
+ if(v == 0xffff)
+ error("phy read");
+ if(v & Smirdone)
+ return gmacread(c, Smidata);
+ microdelay(10);
+ }
+}
+
+static ushort
+phywrite(Ctlr *c, uint r, ushort v)
+{
+ gmacwrite(c, Smidata, v);
+ gmacwrite(c, Smictl, Smiwrite | r<<6);
+ for(;;){
+ v = gmacread(c, Smictl);
+ if(v == 0xffff)
+ error("phy write");
+ if((v & Smibusy) == 0)
+ return gmacread(c, Smidata);
+ microdelay(10);
+ }
+}
+
+static void
+bufinit(Ctlr *c, uint q, uint start, uint end)
+{
+ uint t;
+
+ rrwrite8(c, q + Rctl, Rrstclr);
+ rrwrite32(c, q + Rstart, start);
+ rrwrite32(c, q + Rend, end-1);
+ rrwrite32(c, q + Rwp, start);
+ rrwrite32(c, q + Rrp, start);
+
+ if(q == Qr || q == Qr + Qportsz){
+ t = start-end;
+ rrwrite32(c, q + Rpon, t - 8192/8);
+ rrwrite32(c, q + Rpoff, t - 16384/8);
+ } else
+ rrwrite8(c, q + Rctl, Rsfon);
+ rrwrite8(c, q + Rctl, Renable);
+ rrread8(c, q + Rctl);
+}
+
+static void
+qinit(Ctlr *c, uint queue)
+{
+ qrwrite(c, queue + Qcsr, Qallclr);
+ qrwrite(c, queue + Qcsr, Qgo);
+ qrwrite(c, queue + Qcsr, Qfifoon);
+ qrwrite16(c, queue + Qwm, 0x600); /* magic */
+// qrwrite16(c, queue + Qwm, 0x80); /* pcie magic; assume pcie; no help */
+}
+
+/* initialized prefetching */
+static void
+pinit(Ctlr *c, uint queue, Sring *r)
+{
+ union {
+ uchar u[4];
+ uint l;
+ } u;
+
+ prwrite32(c, queue + Pctl, Prefrst);
+ prwrite32(c, queue + Pctl, Prefrstclr);
+ le32put(u.u, Pciwaddrh(r->r));
+ prwrite32(c, queue + Paddrh, u.l);
+ le32put(u.u, Pciwaddrl(r->r));
+ prwrite32(c, queue + Paddrl, u.l);
+ prwrite16(c, queue + Plidx, r->m);
+ prwrite32(c, queue + Pctl, Prefon);
+ prread32(c, queue + Pctl);
+}
+
+static void
+txinit(Ether *e)
+{
+ Ctlr *c;
+ Sring *r;
+
+ c = e->ctlr;
+ r = &c->tx;
+ if(c->txinit == 1)
+ return;
+ c->txinit = 1;
+ r->wp = 0;
+ r->rp = 0;
+ qinit(c, Qtx);
+ pinit(c, Qtx, &c->tx);
+}
+
+static void
+linkup(Ctlr *c, uint w)
+{
+ static Lock l;
+
+ lock(&l);
+ gmacwrite(c, Ctl, w|gmacread(c, Ctl));
+ unlock(&l);
+}
+
+extern void sfence(void);
+
+static void
+tproc(void *v)
+{
+ Block *b;
+ Ctlr *c;
+ Ether *e;
+ Kproc *k;
+ Sring *r;
+ Status *t;
+
+ e = v;
+ c = e->ctlr;
+ k = &c->txmit;
+ r = &c->tx;
+
+ txinit(e);
+ linkup(c, Txen);
+ for(;;){
+ if((b = qbread(e->oq, 100000)) == nil)
+ break;
+ if(Pciwaddrh(b->rp) != 0){
+ t = getslot(r, k);
+ t->ctl = 0;
+ t->op = Oaddr64 | Hw;
+ le32put(t->status, Pciwaddrh(b->rp));
+ }
+ t = getslot(r, k);
+ c->tbring[t - r->r] = b;
+ le32put(t->status, Pciwaddrl(b->rp));
+ le16put(t->l, BLEN(b));
+ t->op = Opkt | Hw;
+ t->ctl = Eop;
+ sfence();
+ prwrite16(c, Qtx + Pputidx, r->wp & r->m);
+ }
+ print("#l%d: tproc: queue closed\n", e->ctlrno);
+ pexit("queue closed", 1);
+}
+
+static void
+rxinit(Ether *e)
+{
+ int i;
+ Ctlr *c;
+ Block *b;
+ Sring *r;
+ Status *t;
+
+ c = e->ctlr;
+ r = &c->rx;
+ if(c->rxinit == 1)
+ return;
+ c->rxinit = 1;
+ for(i = 0; i < Nrb; i++){
+ b = allocb(c->rbsz + Rbalign);
+ b->free = freetab[c->qno];
+ freeb(b);
+ }
+
+ qinit(c, Qr);
+ if(c->type == Yukecu && (c->rev == 2 || c->rev == 3))
+ qrwrite(c, Qr + Qtest, Qramdis);
+ pinit(c, Qr, &c->rx);
+
+ if((c->flag & Fnewle) == 0){
+ t = getslot(r, &c->rxmit);
+ le32put(t->status, 14<<16 | 14);
+ t->ctl = 0;
+ t->op = Ock | Hw;
+ qrwrite(c, Qr + Qcsr, Qsumen);
+ }
+ macwrite32(c, Gfrxctl, Gftroff);
+}
+
+/* debug; remove */
+#include "yukdump.h"
+static int
+rxscrew(Ether *e, Sring *r, Status *t, uint wp)
+{
+ Ctlr *c;
+
+ c = e->ctlr;
+ if(wp - r->rp > r->cnt){
+ print("rxscrew1 wp %ud(%ud) rp %ud %lud\n", wp, r->wp, r->rp, t-r->r);
+ return -1;
+ }
+ if(c->rbring[t - r->r]){
+ print("rxscrew2 wp %ud rp %ud %lud\n", wp, r->rp, t-r->r);
+ descriptorfu(e, Qr);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+replenish(Ether *e, Ctlr *c)
+{
+ int req, n, lim;
+ uint wp;
+ Block *b;
+ Sring *r;
+ Status *tab[2], *t;
+
+ r = &c->rx;
+ wp = r->wp;
+ req = 1 + is64();
+
+ lim = r->cnt/2;
+ if(lim > 128)
+ lim = 128; /* hw limit? */
+ for(n = 0; n < lim; n++){
+ b = rballoc(c->qno);
+ if(b == nil || getnslot(r, &wp, tab, req) == -1){
+ freeb(b);
+ break;
+ }
+ t = tab[0];
+ if(is64()){
+ le32put(t->status, Pciwaddrh(b->wp));
+ t->ctl = 0;
+ t->op = Oaddr64 | Hw;
+ t = tab[1];
+ }
+ if(rxscrew(e, r, t, wp) == -1)
+ break;
+ assert(c->rbring[t - r->r] == nil);
+ c->rbring[t - r->r] = b;
+
+ le32put(t->status, Pciwaddrl(b->wp));
+ le16put(t->l, c->rbsz);
+ t->ctl = 0;
+ t->op = Opkt | Hw;
+ }
+ if(n>0){
+ sfence();
+ prwrite16(c, Qr + Pputidx, wp & r->m);
+ r->wp = wp;
+ dprint("yuk: replenish %d %ud-%ud [%d-%d]\n", n, r->rp, wp, r->rp&r->m, wp&r->m);
+ }
+ return lim - n == 0;
+}
+
+static void
+rproc(void *v)
+{
+ Ctlr *c;
+ Ether *e;
+ Kproc *k;
+
+ e = v;
+ c = e->ctlr;
+ k = &c->rxmit;
+
+ rxinit(e);
+ linkup(c, Rxen);
+ for(;;)
+ if(replenish(e, c) == 0){
+ starve(k);
+ print("yuk: rx unstarve?\n");
+ }
+}
+
+static void
+promiscuous(void *a, int on)
+{
+ uint r;
+ Ether *e;
+ Ctlr *c;
+
+ e = a;
+ c = e->ctlr;
+ r = gmacread(c, Rxctl);
+ if(on)
+ r &= ~(Ufilter|Mfilter);
+ else
+ r |= Ufilter|Mfilter;
+ gmacwrite(c, Rxctl, r);
+}
+
+static uchar pauseea[] = {1, 0x80, 0xc2, 0, 0, 1};
+
+static void
+multicast(void *a, uchar *ea, int on)
+{
+ uchar f[8];
+ uint i, r, b;
+ Ctlr *c;
+ Ether *e;
+ Mc **ll, *l, *p;
+
+ e = a;
+ c = e->ctlr;
+ r = gmacread(c, Rxctl);
+ if(on){
+ for(ll = &c->mc; *ll != nil; ll = &(*ll)->next)
+ if(memcmp((*ll)->ea, ea, Eaddrlen) == 0)
+ return;
+ *ll = malloc(sizeof **ll);
+ memmove((*ll)->ea, ea, Eaddrlen);
+ }else{
+ for(p = nil, l = c->mc; l != nil; p = l, l = l->next)
+ if(memcmp(l->ea, ea, Eaddrlen) == 0)
+ break;
+ if(l == nil)
+ return;
+ if(p != nil)
+ p->next = l->next;
+ else
+ c->mc = l->next;
+ free(l);
+ }
+ memset(f, 0, sizeof f);
+ if(0 /* flow control */){
+ b = ethercrc(pauseea, Eaddrlen) & 0x3f;
+ f[b>>3] |= 1 << (b & 7);
+ }
+ for(l = c->mc; l != nil; l = l->next){
+ b = ethercrc(l->ea, Eaddrlen) & 0x3f;
+ f[b>>3] |= 1 << (b & 7);
+ }
+ for(i = 0; i < sizeof f / 2; i++)
+ gmacwrite(c, Mchash + 2*i, f[i] | f[i+1]<<8);
+ gmacwrite(c, Rxctl, r | Mfilter);
+}
+
+static int spdtab[4] = {
+ 10, 100, 1000, 0,
+};
+
+static void
+link(Ether *e)
+{
+ uint i, s, spd;
+ Ctlr *c;
+
+ c = e->ctlr;
+ i = phyread(c, Phyint);
+ s = phyread(c, Phylstat);
+ dprint("#l%d: yuk: link %.8ux %.8ux\n", e->ctlrno, i, s);
+ spd = 0;
+ e->link = (s & Plink) != 0;
+ if(e->link && c->feat&Ffiber)
+ spd = 1000;
+ else if(e->link){
+ spd = s & Physpd;
+ spd >>= 14;
+ spd = spdtab[spd];
+ }
+ e->mbps = spd;
+ dprint("#l%d: yuk: link %d spd %d\n", e->ctlrno, e->link, e->mbps);
+}
+
+static void
+txcleanup(Ctlr *c, uint end)
+{
+ uint rp0, rp;
+ Block *b;
+ Sring *r;
+ Status *t;
+
+ r = &c->tx;
+ rp0 = r->rp & r->m;
+ for(rp = rp0; rp != end; rp = r->rp & r->m){
+ t = r->r + rp;
+ r->rp++;
+ if((t->ctl & Eop) == 0)
+ continue;
+ b = c->tbring[rp];
+ c->tbring[rp] = nil;
+ if(b != nil)
+ freeb(b);
+ }
+ if(r->wp - r->rp > 16){ /* BOTCH */
+ print("TX unstarve %ud - %ud \n", r->wp, r->rp);
+ unstarve(&c->txmit);
+ }
+}
+
+static void
+rx(Ether *e, uint l, uint x, uint flag)
+{
+ uint cnt, i, rp;
+ Block *b;
+ Ctlr *c;
+ Sring *r;
+
+ c = e->ctlr;
+ r = &c->rx;
+ for(rp = r->rp;;){
+ i = rp++&r->m;
+ b = c->rbring[i];
+ c->rbring[i] = nil;
+ if(b != nil)
+ break;
+ }
+ cnt = x>>16 & 0x7fff;
+ if(cnt != l || x&Rxerror &&
+ !(c->type == Yukfep && c->rev == 0)){
+ print("#l%d: yuk rx error %.4ux\n", e->ctlrno, x&0xffff);
+ freeb(b);
+ }else{
+ b->wp += l;
+ b->lim = b->wp; /* lie like a dog */
+ b->flag |= flag;
+ etheriq(e, b, 1);
+ }
+ r->rp = rp;
+}
+
+static uint
+cksum(Ctlr *c, uint ck, uint css)
+{
+ if(c->flag & Fnewle && css&(Cisip4|Cisip6) && css&Ctcpok)
+ return Bipck | Btcpck | Budpck;
+ else if(ck == 0xffff || ck == 0)
+ return Bipck;
+ return 0;
+}
+
+static void
+sring(Ether *e)
+{
+ uint i, p, lim, op, l, x;
+ Ctlr *c;
+ Sring *r;
+ Status *s;
+ static uint ck = Badck;
+
+ c = e->ctlr;
+ r = &c->status;
+ lim = r->rp & r->m;
+ p = 0;
+ for(;;){
+ if((r->rp & r->m) == lim){
+ lim = c->reg16[Stathd];
+ if((r->rp & r->m) == lim)
+ break;
+ }
+ i = r->rp & r->m;
+ s = r->r + i;
+ op = s->op;
+ if((op & Hw) == 0)
+ break;
+ op &= ~Hw;
+ switch(op){
+ case Orxchks:
+ ck = gbit32(s->status) & 0xffff;
+ break;
+ case Orxstat:
+ l = gbit16(s->l);
+ x = gbit32(s->status);
+ rx(e, l, x, cksum(c, ck, s->ctl));
+ ck = Badck;
+ p++;
+ break;
+ case Otxidx:
+ l = gbit16(s->l);
+ x = gbit32(s->status);
+ txcleanup(c, x & 0xfff);
+
+ x = l>>24 & 0xff | l<< 8;
+ x &= 0xfff;
+ if(x != 0 && c->oport)
+ txcleanup(c->oport, x);
+ break;
+ default:
+ print("#l%d: yuk: funny opcode %.2ux\n", e->ctlrno, op);
+ break;
+ }
+ s->op = 0;
+ r->rp++;
+ }
+ while(p && replenish(e, c) != 0)
+ ;
+ c->reg[Statctl] = Statirqclr;
+}
+
+enum {
+ Pciaer = 0x1d00,
+ Pciunc = 0x0004,
+};
+
+static void
+hwerror(Ether *e, uint cause)
+{
+ uint u;
+ Ctlr *c;
+
+ c = e->ctlr;
+ cause = c->reg[Hwe];
+ if(cause == 0)
+ print("hwe: no cause\n");
+ if(cause & Htsof){
+ c->reg8[Tgc] = Tgclr;
+ cause &= ~Htsof;
+ }
+ if(cause & (Hmerr | Hstatus)){
+ c->reg8[Tstctl1] = Tstwen;
+ u = pcicfgr16(c->p, PciPSR) | 0x7800;
+ pcicfgw16(c->p, PciPSR, u);
+ c->reg8[Tstctl1] = Tstwdis;
+ cause &= ~(Hmerr | Hstatus);
+ }
+ if(cause & Hpcie){
+ c->reg8[Tstctl1] = Tstwen;
+ c->reg[Pciaer + Pciunc>>2] = ~0;
+ u = c->reg[Pciaer + Pciunc>>2];
+ USED(u);
+ print("#l%d: pcierror %.8ux\n", e->ctlrno, u);
+ c->reg8[Tstctl1] = Tstwdis;
+ cause &= ~Hpcie;
+ }
+ if(cause & Hrxparity){
+ print("#l%d: ram parity read error. bug? ca %.8ux\n", e->ctlrno, cause);
+ qrwrite(c, Qtx + Qcsr, Qcirqpar);
+ cause &= ~Hrxparity;
+ }
+ if(cause & Hrparity){
+ print("#l%d: ram parity read error. bug? ca %.8ux\n", e->ctlrno, cause);
+ descriptorfu(e, Qr);
+ descriptorfu(e, Qtx);
+ c->reg16[Rictl + c->portno*0x40>>1] = Rirpclr;
+ cause &= ~Hrparity;
+ }
+ if(cause & Hwparity){
+ print("#l%d: ram parity write error. bug? ca %.8ux\n", e->ctlrno, cause);
+ descriptorfu(e, Qr);
+ descriptorfu(e, Qtx);
+ c->reg16[Rictl + c->portno*0x40>>1] = Riwpclr;
+ cause &= ~Hwparity;
+ }
+ if(cause & Hmfault){
+ print("#l%d: mac parity error\n", e->ctlrno);
+ macwrite32(c, Gmfctl, Gmfcpe);
+ cause &= ~Hmfault;
+ }
+ if(cause)
+ print("#l%d: leftover hwe %.8ux\n", e->ctlrno, cause);
+}
+
+static void
+macintr(Ether *e)
+{
+ uint cause;
+ Ctlr *c;
+
+ c = e->ctlr;
+ cause = macread8(c, Irq);
+ cause &= ~(Rxdone | Txdone);
+ if(cause == 0)
+ return;
+ print("#l%d: mac error %.8ux\n", e->ctlrno, cause);
+ if(cause & Txovfl){
+ gmacread32(c, Txirq);
+ cause &= ~Txovfl;
+ }
+ if(cause & Rxovfl){
+ gmacread32(c, Rxirq);
+ cause &= ~Rxovfl;
+ }
+ if(cause & Rxorun){
+ macwrite32(c, Gfrxctl, Gmfcfu);
+ cause &= ~Rxorun;
+ }
+ if(cause & Txurun){
+ macwrite32(c, Gmfctl, Gmfcfu);
+ cause &= ~Txurun;
+ }
+ if(cause)
+ print("#l%d: leftover mac error %.8ux\n", e->ctlrno, cause);
+}
+
+static struct {
+ uint i;
+ uint q;
+ char *s;
+} emap[] = {
+ Irx, Qr, "qr",
+ Itxs, Qtxs, "qtxs",
+ Itx, Qtx, "qtx",
+ Irx<<Iphy2base, Qr + 0x80, "qr1",
+ Itxs<<Iphy2base, Qtxs + 0x100, "qtxs1",
+ Itx<<Iphy2base, Qtx + 0x100, "qtx1",
+};
+
+static void
+eerror(Ether *e, uint cause)
+{
+ uint i, o, q;
+ Ctlr *c;
+
+ c = e->ctlr;
+
+ if(cause & Imac){
+ macintr(e);
+ cause &= ~Imac;
+ }
+ if(cause & (Irx | Itxs | Itx)*(1 | 1<<Iphy2base))
+ for(i = 0; i < nelem(emap); i++){
+ if((cause & emap[i].i) == 0)
+ continue;
+ q = emap[i].q;
+ o = prread16(c, q + Pgetidx);
+ print("#l%d: yuk: bug: %s: @%d ca=%.8ux\n",
+ e->ctlrno, emap[i].s, o, cause);
+ descriptorfu(e, q);
+ qrwrite(c, emap[i].q + Qcsr, Qcirqck);
+ cause &= ~emap[i].i;
+ }
+ if(cause)
+ print("#l%d: leftover error %.8ux\n", e->ctlrno, cause);
+}
+
+static void
+iproc(void *v)
+{
+ uint cause, d;
+ Ether *e;
+ Ctlr *c;
+ Kproc *k;
+
+ e = v;
+ c = e->ctlr;
+ k = &c->iproc;
+
+ for(;;){
+ starve(k);
+ cause = c->reg[Eisr];
+ if(cause & Iphy)
+ link(e);
+ if(cause & Ihwerr)
+ hwerror(e, cause);
+ if(cause & Ierror)
+ eerror(e, cause & Ierror);
+ if(cause & Ibmu)
+ sring(e);
+ d = c->reg[Lisr];
+ USED(d);
+ }
+}
+
+static void
+interrupt(Ureg*, void *v)
+{
+ uint cause;
+ Ctlr *c;
+ Ether *e;
+
+ e = v;
+ c = e->ctlr;
+
+ cause = c->reg[Isrc2];
+ if(cause != 0 && cause != ~0)
+ unstarve(&c->iproc);
+}
+
+static void
+storefw(Ctlr *c)
+{
+ if(c->type == Yukex && c->rev != 1
+ || c->type == Yukfep
+ || c->type == Yuksup)
+ macwrite32(c, Gmfctl, Gmfjon | Gmfsfon);
+ else{
+ macwrite32(c, Gmfae, 0x8000 | 0x70); /* tx gmac fifo */
+ macwrite32(c, Gmfctl, Gmfsfoff);
+ }
+}
+
+static void
+raminit(Ctlr *c)
+{
+ uint ram, rx;
+
+ if(ram = c->reg8[Ramcnt] * 4096/8){ /* in qwords */
+ c->flag |= Fram;
+ rx = ROUNDUP((2*ram)/3, 1024/8);
+ bufinit(c, Qr, 0, rx);
+ bufinit(c, Qtx, rx, ram);
+ rrwrite8(c, Qtxs + Rctl, Rrst); /* sync tx off */
+ }else{
+ macwrite8(c, Rxplo, 768/8);
+ macwrite8(c, Rxphi, 1024/8);
+ storefw(c);
+ }
+}
+
+static void
+attach(Ether *e)
+{
+ char buf[KNAMELEN];
+ Ctlr *c;
+ static Lock l;
+
+ c = e->ctlr;
+ if(c->attach == 1)
+ return;
+ lock(&l);
+ if(c->attach == 1){
+ unlock(&l);
+ return;
+ }
+ c->attach = 1;
+ unlock(&l);
+
+ snprint(buf, sizeof buf, "#l%dtproc", e->ctlrno);
+ kproc(buf, tproc, e);
+ snprint(buf, sizeof buf, "#l%drproc", e->ctlrno);
+ kproc(buf, rproc, e);
+ snprint(buf, sizeof buf, "#l%diproc", e->ctlrno);
+ kproc(buf, iproc, e);
+
+ c->reg[Ism] |= Ibmu | Iport<<Iphy2base*c->portno;
+}
+
+static long
+ifstat(Ether *e0, void *a, long n, ulong offset)
+{
+ char *s, *e, *p;
+ int i;
+ uint u;
+ Ctlr *c;
+
+ c = e0->ctlr;
+ p = s = malloc(READSTR);
+ e = p + READSTR;
+ for(i = 0; i < nelem(stattab); i++){
+ u = gmacread32(c, Stats + stattab[i].offset/4);
+ if(u > 0)
+ p = seprint(p, e, "%s\t%ud\n", stattab[i].name, u);
+ }
+ p = seprint(p, e, "stat %.4ux ctl %.3ux\n", gmacread(c, Stat), gmacread(c, Ctl));
+// p = seprint(p, e, "irq %.8ux\n", c->reg[Isrc2]);
+ p = seprint(p, e, "pref %.8ux %.4ux\n", prread32(c, Qr + Pctl), prread16(c, Qr + Pgetidx));
+ p = seprint(p, e, "nfast %ud nslow %ud\n", rbtab[c->qno].nfast, rbtab[c->qno].nslow);
+ if(debug){
+ p = dumppci(c, p, e);
+ p = dumpgmac(c, p, e);
+ p = dumpmac(c, p, e);
+ p = dumpreg(c, p, e);
+ }
+ seprint(p, e, "%s rev %d phy %s\n", idtab[c->type].name,
+ c->rev, c->feat&Ffiber? "fiber": "copper");
+ n = readstr(offset, a, n, s);
+ free(s);
+ return n;
+}
+
+static Cmdtab ctltab[] = {
+ 1, "debug", 1,
+ 2, "descriptorfu", 1,
+};
+
+static long
+ctl(Ether *e, void *buf, long n)
+{
+ Cmdbuf *cb;
+ Cmdtab *t;
+
+ cb = parsecmd(buf, n);
+ if(waserror()){
+ free(cb);
+ nexterror();
+ }
+ t = lookupcmd(cb, ctltab, nelem(ctltab));
+ switch(t->index){
+ case 0:
+ debug ^= 1;
+ break;
+ case 1:
+ descriptorfu(e, Qr);
+ break;
+ }
+ free(cb);
+ poperror();
+ return n;
+}
+
+static uint
+yukpcicfgr32(Ctlr *c, uint r)
+{
+ return c->reg[r + 0x1c00>>2];
+}
+
+static void
+yukpcicfgw32(Ctlr *c, uint r, uint v)
+{
+ c->reg[r + 0x1c00>>2] = v;
+}
+
+static void
+phypower(Ctlr *c)
+{
+ uint u, u0;
+
+ u = u0 = yukpcicfgr32(c, Pciphy);
+ u &= ~phypwr[c->portno];
+ if(c->type == Yukxl && c->rev > 1)
+ u |= coma[c->portno];
+ if(u != u0 || 1){
+ c->reg8[Tstctl1] = Tstwen;
+ yukpcicfgw32(c, Pciphy, u);
+ c->reg8[Tstctl1] = Tstwdis;
+ }
+ if(c->type == Yukfe)
+ c->reg8[Phyctl] = Aneen;
+ else if(c->flag & Fapwr)
+ macwrite32(c, Phy, Gphyrstclr);
+}
+
+static void
+phyinit(Ctlr *c)
+{
+ uint u;
+
+ if((c->feat & Fnewphy) == 0){
+ u = phyread(c, Phyextctl);
+ u &= ~0xf70; /* clear downshift counters */
+ u |= 0x7<<4; /* mac tx clock = 25mhz */
+ if(c->type == Yukec)
+ u |= 2*Dnmstr | Dnslv;
+ else
+ u |= Dnslv;
+ phywrite(c, Phyextctl, u);
+ }
+ u = phyread(c, Phyphy);
+
+ /* questionable value */
+ if(c->feat & Ffiber)
+ u &= ~Ppmdix;
+ else if(c->feat & Fgbe){
+ u &= ~Pped;
+ u |= Ppmdixa;
+ if(c->flag & Fnewphy){
+ // u &= ~(7<<12);
+ // u |= 2*(1<<12) | 1<<11; /* like 2*Dnmstr | Dnslv */
+ u |= 2*(1<<9) | 1<<11;
+ }
+ }else
+ u |= Ppmdixa >> 1; /* why the shift? */
+
+ phywrite(c, Phyphy, u);
+ /* copper/fiber specific stuff gmacwrite(c, Ctl, 0); */
+ gmacwrite(c, Ctl, 0);
+ if(c->feat & Fgbe)
+ if(c->feat & Ffiber)
+ phywrite(c, Gbectl, Gbexf | Gbexh);
+ else
+ phywrite(c, Gbectl, Gbef | Gbeh);
+ phywrite(c, Phyana, Anall);
+ phywrite(c, Phyctl, Phyrst | Anerst | Aneen);
+ /* chip specific stuff? */
+ if(c->type == Yukfep){
+ u = phyread(c, Phyphy) | Ppnpe;
+ u &= ~(Ppengy | Ppscrdis);
+ phywrite(c, Phyphy, u);
+
+ /* yukfep and rev 0: apply workaround for integrated resistor calibration */
+// phywrite(c, 0x16, 0x0b54); /* write to fe_led_par */
+ phywrite(c, Phypadr, 17);
+ phywrite(c, 0x1e, 0x3f60);
+ }
+ phywrite(c, Phyintm, Anok | Anerr | Lsc);
+ dprint("phyid %.4ux step %.4ux\n", phyread(c, 2), phyread(c, 3));
+}
+
+static int
+identify(Ctlr *c)
+{
+ char t;
+
+ pcicfgw32(c->p, Pciclk, 0);
+ c->reg16[Ctst] = Swclr;
+
+ c->type = c->reg8[Chip] - 0xb3;
+ c->rev = c->reg8[Maccfg]>>4 & 0xf;
+ if(c->type >= Nyuk)
+ return -1;
+ if(idtab[c->type].okrev != 0xff)
+ if(c->rev != idtab[c->type].okrev)
+ return -1;
+ c->feat |= idtab[c->type].feat;
+
+ t = c->reg8[Pmd];
+ if(t == 'L' || t == 'S' || t == 'P')
+ c->feat |= Ffiber;
+ c->portno = 0;
+ /* check second port ... whatever */
+ return 0;
+}
+
+static uint
+µ2clk(Ctlr *c, int µs)
+{
+ return idtab[c->type].mhz * µs;
+}
+
+static void
+gmacsetea(Ctlr *c, uint r)
+{
+ uchar *ra;
+ int i;
+
+ ra = c->ra;
+ for(i = 0; i < Eaddrlen; i += 2)
+ gmacwrite(c, r + i, ra[i + 0] | ra[i + 1]<<8);
+}
+
+static int
+reset(Ctlr *c)
+{
+ uint i, j;
+ Block *b;
+
+ identify(c);
+
+ if(c->type == Yukex)
+ c->reg16[Asfcs/2] &= ~(Asfbrrst | Asfcpurst | Asfucrst);
+ else
+ c->reg8[Asfcs] = Asfrst;
+ c->reg16[Ctst] = Asfdis;
+
+ c->reg16[Ctst] = Swrst;
+ c->reg16[Ctst] = Swclr;
+
+ c->reg8[Tstctl1] = Tstwen;
+ pcicfgw16(c->p, PciPSR, pcicfgr16(c->p, PciPSR) | 0xf100);
+ c->reg16[Ctst] = Mstrclr;
+ /* fixup pcie extended error goes here */
+
+ c->reg8[Pwrctl] = Vauxen | Vccen | Vauxoff | Vccon;
+ c->reg[Clkctl] = Clkdivdis;
+ if(c->type == Yukxl && c->rev > 1)
+ c->reg8[Clkgate] = ~Link2inactive;
+ else
+ c->reg8[Clkgate] = 0;
+ if(c->flag & Fapwr){
+ pcicfgw32(c->p, Pciclk, 0);
+ pcicfgw32(c->p, Pciasp, pcicfgr32(c->p, Pciasp) & Aspmsk);
+ pcicfgw32(c->p, Pcistate, pcicfgr32(c->p, Pcistate) & Vmain);
+ pcicfgw32(c->p, Pcicf1, 0);
+ c->reg[Gpio] |= Norace;
+ print("yuk2: advanced power %.8ux\n", c->reg[Gpio]);
+ }
+ c->reg8[Tstctl1] = Tstwdis;
+
+ for(i = 0; i < c->nports; i++){
+ macwrite8(c, Linkctl, Linkrst);
+ macwrite8(c, Linkctl, Linkclr);
+ if(c->type == Yukex || c->type == Yuksup)
+ macwrite16(c, Mac, Nomacsec | Nortx);
+ }
+
+ c->reg[Dpolltm] = Pollstop;
+
+ for(i = 0; i < c->nports; i++)
+ macwrite8(c, Txactl, Txaclr);
+ for(i = 0; i < c->nports; i++){
+ c->reg8[i*64 + Rictl] = Riclr;
+ for(j = 0; j < 12; j++)
+ c->reg8[i*64 + Rib + j] = 36; /* qword times */
+ }
+
+ c->reg[Hwem] = Hdflt;
+ macwrite8(c, Irqm, 0);
+ for(i = 0; i < 4; i++)
+ gmacwrite(c, Mchash + 2*i, 0);
+ gmacwrite(c, Rxctl, Ufilter | Mfilter | Rmcrc);
+
+ for(i = 0; i < nelem(c->tbring); i++)
+ if(b = c->tbring[i]){
+ c->tbring[i] = nil;
+ freeb(b);
+ }
+ for(i = 0; i < nelem(c->rbring); i++)
+ if(b = c->rbring[i]){
+ c->rbring[i] = nil;
+ freeb(b);
+ }
+
+ memset(c->tbring, 0, sizeof c->tbring[0] * nelem(c->tbring));
+ memset(c->rbring, 0, sizeof c->rbring[0] * nelem(c->rbring));
+ memset(c->tx.r, 0, sizeof c->tx.r[0] * c->tx.cnt);
+ memset(c->rx.r, 0, sizeof c->rx.r[0] * c->rx.cnt);
+ memset(c->status.r, 0, sizeof c->status.r[0] * c->status.cnt);
+ c->reg[Statctl] = Statrst;
+ c->reg[Statctl] = Statclr;
+ c->reg[Stataddr + 0] = Pciwaddrl(c->status.r);
+ c->reg[Stataddr + 4] = Pciwaddrh(c->status.r);
+ c->reg16[Stattl] = c->status.m;
+ c->reg16[Statth] = 10;
+ c->reg8[Statwm] = 16;
+ if(c->type == Yukxl && c->rev == 0)
+ c->reg8[Statiwm] = 4;
+ else
+ c->reg8[Statiwm] = 4; //16;
+
+ /* set transmit, isr, level timers */
+ c->reg[Tsti] = µ2clk(c, 1000);
+ c->reg[Titi] = µ2clk(c, 20);
+ c->reg[Tlti] = µ2clk(c, 100);
+
+ c->reg[Statctl] = Staton;
+
+ c->reg8[Tstc] = Tstart;
+ c->reg8[Tltc] = Tstart;
+ c->reg8[Titc] = Tstart;
+
+ return 0;
+}
+
+static void
+macinit(Ctlr *c)
+{
+ uint r, i;
+
+ r = macread32(c, Phy) & ~(Gphyrst | Gphyrstclr);
+ macwrite32(c, Phy, r | Gphyrst);
+ macwrite32(c, Phy, r | Gphyrstclr);
+ /* macwrite32(c, Mac, Macrst); ? */
+ macwrite32(c, Mac, Macrstclr);
+
+ if(c->type == Yukxl && c->rev == 0 && c->portno == 1){
+ }
+
+ macread8(c, Irq);
+ macwrite8(c, Irqm, Txurun);
+
+ phypower(c);
+ phyinit(c);
+
+ gmacwrite(c, Phyaddr, (r = gmacread(c, Phyaddr)) | Mibclear);
+ for(i = 0; i < nelem(stattab); i++)
+ gmacread32(c, Stats + stattab[i].offset/4);
+ gmacwrite(c, Phyaddr, r);
+
+ gmacwrite(c, Txctl, 4<<10); /* collision distance */
+ gmacwrite(c, Txflow, 0xffff); /* flow control */
+ gmacwrite(c, Txparm, 3<<14 | 0xb<<9 | 0x1c<<4 | 4);
+ gmacwrite(c, Rxctl, Ufilter | Mfilter | Rmcrc);
+ gmacwrite(c, Serctl, 0x04<<11 /* blind */ | Jumboen | 0x1e /* ipig */);
+
+ gmacsetea(c, Ea0);
+ gmacsetea(c, Ea1);
+
+ gmacwrite(c, Txmask, 0);
+ gmacwrite(c, Rxmask, 0);
+ gmacwrite(c, Trmask, 0);
+
+ macwrite32(c, Gfrxctl, Gfrstclr);
+ r = Gfon | Gffon;
+ if(c->type == Yukex || c->type == Yukfep)
+ r |= Gfroon;
+ macwrite32(c, Gfrxctl, r);
+ if(c->type == Yukxl)
+ macwrite32(c, Grxfm, 0);
+ else
+ macwrite32(c, Grxfm, Ferror);
+ if(c->type == Yukfep && c->rev == 0)
+ macwrite32(c, Grxft, 0x178);
+ else
+ macwrite32(c, Grxft, 0xb);
+
+ macwrite32(c, Gmfctl, Gmfclr); /* clear reset */
+ macwrite32(c, Gmfctl, Gmfon); /* on */
+
+ raminit(c);
+ if(c->type == Yukfep && c->rev == 0)
+ c->reg[Gmfea] = c->reg[Gmfea] & ~3;
+
+ c->rxinit = 0;
+ c->txinit = 0;
+}
+
+static void*
+slice(void **v, uint r, uint sz)
+{
+ uintptr a;
+
+ a = (uintptr)*v;
+ a = ROUNDUP(a, r);
+ *v = (void*)(a + sz);
+ return (void*)a;
+}
+
+static void
+setupr(Sring *r, uint cnt)
+{
+ r->rp = 0;
+ r->wp = 0;
+ r->cnt = cnt;
+ r->m = cnt - 1;
+}
+
+static int
+setup(Ctlr *c)
+{
+ uint n;
+ void *v, *mem;
+ Pcidev *p;
+
+ p = c->p;
+ mem = vmap(c->io, p->mem[0].size);
+ if(mem == nil){
+ print("yuk: cant map %#ulx\n", c->io);
+ return -1;
+ }
+ c->p = p;
+ c->reg = (uint*)mem;
+ c->reg8 = (uchar*)mem;
+ c->reg16 = (ushort*)mem;
+ if(memcmp(c->ra, nilea, sizeof c->ra) == 0)
+ memmove(c->ra, c->reg8 + Macadr + 8*c->portno, Eaddrlen);
+
+ setupr(&c->status, Sringcnt);
+ setupr(&c->tx, Tringcnt);
+ setupr(&c->rx, Rringcnt);
+
+ n = sizeof c->status.r[0] * (c->status.cnt + c->tx.cnt + c->rx.cnt);
+ n += 16*4096*2; /* rounding slop */
+ c->alloc = xspanalloc(n, 16*4096, 0); /* unknown alignment constraints */
+ memset(c->alloc, 0, n);
+
+ v = c->alloc;
+ c->status.r = slice(&v, 16*4096, sizeof c->status.r[0] * c->status.cnt);
+ c->tx.r = slice(&v, 16*4096, sizeof c->tx.r[0] * c->tx.cnt);
+ c->rx.r = slice(&v, 16*4096, sizeof c->rx.r[0] * c->rx.cnt);
+
+ c->nports = 1; /* BOTCH */
+ pcisetbme(p);
+ if(reset(c)){
+ print("yuk: cant reset\n");
+ pciclrbme(p);
+ free(c->alloc);
+ vunmap(mem, p->mem[0].size);
+ return -1;
+ }
+ macinit(c);
+ return 0;
+}
+
+static void
+shutdown(Ether *e)
+{
+ Ctlr *c;
+ Pcidev *p;
+
+ c = e->ctlr;
+
+ reset(c);
+ if(0){
+ p = c->p;
+ vunmap(c->reg, p->mem[0].size);
+ free(c->alloc);
+ }
+}
+
+static void
+scan(void)
+{
+ int i;
+ Pcidev *p;
+ Ctlr *c;
+
+ for(p = nil; p = pcimatch(p, 0, 0); ){
+ for(i = 0; i < nelem(vtab); i++)
+ if(vtab[i].vid == p->vid)
+ if(vtab[i].did == p->did)
+ break;
+ if(i == nelem(vtab))
+ continue;
+ if(nctlr == nelem(ctlrtab)){
+ print("yuk: too many controllers\n");
+ return;
+ }
+ c = malloc(sizeof *c);
+ c->p = p;
+ c->io = p->mem[0].bar & ~(uintptr)0xf;
+ c->qno = nctlr;
+ rbtab[c->qno].k = &c->rxmit;
+ c->rbsz = vtab[i].mtu;
+ ctlrtab[nctlr++] = c;
+ }
+}
+
+static int
+pnp(Ether *e)
+{
+ int i;
+ Ctlr *c;
+
+ if(nctlr == 0)
+ scan();
+ for(i = 0;; i++){
+ if(i == nctlr)
+ return -1;
+ c = ctlrtab[i];
+ if(c == nil || c->flag&Fprobe)
+ continue;
+ if(e->port != 0 && e->port != (ulong)c->reg)
+ continue;
+ c->flag |= Fprobe;
+ if(setup(c) != 0)
+ continue;
+ break;
+ }
+ e->ctlr = c;
+ e->port = c->io;
+ e->irq = c->p->intl;
+ e->tbdf = c->p->tbdf;
+ e->mbps = 1000;
+ e->maxmtu = c->rbsz;
+ memmove(e->ea, c->ra, Eaddrlen);
+ e->arg = e;
+ e->attach = attach;
+ e->ctl = ctl;
+ e->ifstat = ifstat;
+ e->interrupt = interrupt;
+ e->multicast = multicast;
+ e->promiscuous = promiscuous;
+ e->shutdown = shutdown;
+ e->transmit = nil;
+
+ return 0;
+}
+
+void
+etheryuklink(void)
+{
+ addethercard("yuk", pnp);
+}
--- /sys/src/9/pc/yukdump.h Wed Feb 24 00:00:00 2016
+++ /sys/src/9/pc/yukdump.h Wed Feb 24 00:00:00 2016
@@ -0,0 +1,319 @@
+typedef struct Regdump Regdump;
+struct Regdump {
+ uint offset;
+ uint size;
+ char *name;
+};
+
+Regdump pcireg[] = {
+ Pciphy, 32, "Pciphy",
+ Pciclk, 32, "Pciclk",
+ Pcistate, 32, "Pcistate",
+};
+
+static Regdump gmacreg[] = {
+ Stat, 16, "Stat",
+ Ctl, 16, "Ctl",
+ Txctl, 16, "Txctl",
+ Rxctl, 16, "Rxctl",
+ Txflow, 16, "Txflow",
+ Txparm, 16, "Txparm",
+ Serctl, 16, "Serctl",
+ Txirq, 16, "Txirq",
+ Rxirq, 16, "Rxirq",
+ Trirq, 16, "Trirq",
+ Txmask, 16, "Txmask",
+ Rxmask, 16, "Rxmask",
+ Trmask, 16, "Trmask",
+ Smictl, 16, "Smictl",
+ Smidata, 16, "Smidata",
+ Phyaddr, 16, "Phyaddr",
+ Mchash+0, 16, "Mchash",
+ Mchash+2, 16, "Mchash",
+ Mchash+4, 16, "Mchash",
+ Mchash+6, 16, "Mchash",
+ Ea0, 16, "Ea0",
+ Ea0+2, 16, "Ea0",
+ Ea0+4, 16, "Ea0",
+ Ea1, 16, "Ea1",
+ Ea1+2, 16, "Ea1",
+ Ea1+4, 16, "Ea1",
+};
+
+static Regdump macreg[] = {
+ Txactl, 8, "Txactl",
+ Gfrxctl, 32, "Gfrxctl",
+ Grxfm, 32, "Grxfm",
+ Grxft, 32, "Grxft",
+ Grxtt, 32, "Grxtt",
+ Gmfctl, 32, "Gmfctl",
+ Mac, 32, "Mac",
+ Phy, 32, "Phy",
+ Irqm, 8, "Irqm",
+ Linkctl, 8, "Linkctl",
+
+ Rxwp, 32, "Rxwp",
+ Rxrp, 32, "Rxrp",
+ Rxrlev, 32, "Rxrlev",
+
+};
+
+static Regdump reg[] = {
+ Ctst, 16, "Ctst",
+ Pwrctl, 8, "Pwrctl",
+ Isr, 32, "Isr",
+ Ism, 32, "Ism",
+ Hwe, 32, "Hwe",
+ Hwem, 32, "Hwem",
+ Isrc2, 32, "Isrc2",
+
+ Macadr/2, 16, "Macadr",
+ Macadr/2+1, 16, "Macadr",
+ Macadr/2+2, 16, "Macadr",
+
+ Pmd, 8, "Pmd",
+ Maccfg, 8, "Maccfg",
+ Chip, 8, "Chip",
+ Ramcnt, 8, "Ramcnt",
+ Clkgate, 8, "Clkgate",
+ Hres, 8, "Hres",
+ Clkctl, 32, "Clkctl",
+ Tstctl1, 8, "Tstctl1",
+
+ Asfcs, 8, "Asfcs",
+ Asfhost, 32, "Asfhost",
+ Statctl, 32, "Statctl",
+ Stattl, 16, "Stattl",
+ Stataddr, 32, "Stataddr",
+ Statth, 16, "Statth",
+ Stathd, 16, "Stathd",
+ Statwm, 8, "Statwm",
+ Statiwm, 8, "Statiwm",
+};
+
+static char*
+dumppci(Ctlr *c, char *p, char *e)
+{
+ int i;
+ Regdump *r;
+
+ r = pcireg;
+ p = seprint(p, e, "/* pci reg */\n");
+ for(i = 0; i < nelem(pcireg); i++)
+ switch(r[i].size){
+ default:
+ p = seprint(p, e, "%s: bug size %d\n", r[i].name, r[i].size);
+ break;
+ case 32:
+ p = seprint(p, e, "%s: %.8ux\n", r[i].name, pcicfgr32(c->p, r[i].offset));
+ break;
+ }
+ return p;
+}
+
+static char*
+dumpgmac(Ctlr *c, char *p, char *e)
+{
+ int i;
+ Regdump *r;
+
+ r = gmacreg;
+ p = seprint(p, e, "/* gmac reg */\n");
+ for(i = 0; i < nelem(gmacreg); i++)
+ switch(r[i].size){
+ default:
+ p = seprint(p, e, "%s: bug size %d\n", r[i].name, r[i].size);
+ break;
+ case 16:
+ p = seprint(p, e, "%s: %.4ux\n", r[i].name, gmacread(c, r[i].offset));
+ break;
+ case 32:
+ p = seprint(p, e, "%s: %.8ux\n", r[i].name, gmacread32(c, r[i].offset));
+ break;
+ }
+ return p;
+}
+
+static char*
+dumpmac(Ctlr *c, char *p, char *e)
+{
+ int i;
+ Regdump *r;
+
+ r = macreg;
+ p = seprint(p, e, "/* mac reg */\n");
+ for(i = 0; i < nelem(macreg); i++)
+ switch(r[i].size){
+ default:
+ p = seprint(p, e, "%s: bug size %d\n", r[i].name, r[i].size);
+ break;
+ case 8:
+ p = seprint(p, e, "%s: %.2ux\n", r[i].name, macread8(c, r[i].offset));
+ break;
+ case 32:
+ p = seprint(p, e, "%s: %.8ux\n", r[i].name, macread32(c, r[i].offset));
+ break;
+ }
+ return p;
+}
+
+static char*
+dumpreg(Ctlr *c, char *p, char *e)
+{
+ int i;
+ Regdump *r;
+
+ r = reg;
+ p = seprint(p, e, "/* reg */\n");
+ for(i = 0; i < nelem(reg); i++)
+ switch(r[i].size){
+ default:
+ p = seprint(p, e, "%s: bug size %d\n", r[i].name, r[i].size);
+ break;
+ case 8:
+ p = seprint(p, e, "%s: %.2ux\n", r[i].name, c->reg8[r[i].offset]);
+ break;
+ case 16:
+ p = seprint(p, e, "%s: %.4ux\n", r[i].name, c->reg16[r[i].offset]);
+ break;
+ case 32:
+ p = seprint(p, e, "%s: %.8ux\n", r[i].name, c->reg[r[i].offset]);
+ break;
+ }
+ return p;
+}
+
+static char *optab[256] = {
+[Orxchks] "rxsum",
+[Orxstat] "rxstat",
+[Otxidx] "txidx",
+};
+
+static char*
+rs(uint r)
+{
+ char *s;
+
+ s = optab[r & 0xff];
+ if(s == nil)
+ s = "";
+ return s;
+}
+
+static int
+nblocktab(int qno)
+{
+ uint i;
+ Block *b;
+
+ ilock(&rbtab[qno]);
+ b = rbtab[qno].b;
+ for(i = 0;; i++){
+ if(b == nil)
+ break;
+ b = b->next;
+ }
+ iunlock(&rbtab[qno]);
+ return i;
+}
+
+static char*
+dumpring(Sring *r, Block **t, int qno, char *p, char *e)
+{
+ int m, n;
+ uint i;
+
+ p = seprint(p, e,
+ "bring: rp %ud wp %ud cnt %ud m %ud : ",
+ r->rp, r->wp, r->cnt, r->m);
+ m = -1;
+ n = 0;
+ for(i = 0; i < r->cnt; i++){
+ n += t[i] != nil;
+ if(m>=0 && t[i] == nil){
+ p = seprint(p, e, "%ud", m);
+ if(i != m + 1)
+ p = seprint(p, e, "-%ud", i-1);
+ p = seprint(p, e, " ");
+ m = -1;
+ }else if(m<0 && t[i] != nil)
+ m = i;
+ }
+ if(m>=0){
+ p = seprint(p, e, "%ud", m);
+ if(i != m + 1)
+ p = seprint(p, e, "-%ud ", i-1);
+ }
+ p = seprint(p, e, "n=%d/%d", n, r->cnt);
+ return seprint(p, e, " list %d\n", nblocktab(qno));
+}
+
+static ushort
+gbit16(void *a)
+{
+ uchar *i;
+
+ i = a;
+ return i[1]<<8 | i[0];
+}
+
+static ulong
+gbit32(void *a)
+{
+ ulong j;
+ uchar *i;
+
+ i = a;
+ j = i[3] << 24;
+ j |= i[2] << 16;
+ j |= i[1] << 8;
+ j |= i[0];
+ return j;
+}
+
+/* debug; remove */
+static void
+descriptorfu(Ether *e, uint qoff)
+{
+ char buf[PRINTSIZE], *p, *f;
+ uint q, qm1;
+ Block *b, *a, **bring;
+ Ctlr *c;
+ Status *t, *v;
+ Sring *r;
+
+ c = e->ctlr;
+ f = buf + sizeof buf;
+ if(qoff == Qtx){
+ bring = c->tbring;
+ r = &c->tx;
+ p = seprint(buf, f, "tx ");
+ }else{
+ bring = c->rbring;
+ r = &c->rx;
+ p = seprint(buf, f, "rx ");
+ }
+
+ q = prread16(c, qoff + Pgetidx);
+ print(" getidx %ud\n", q);
+ if(q >= r->cnt){
+ q &= r->m;
+ print(" try getidx %ud\n", q);
+ }
+ qm1 = q-1 & r->m;
+ t = r->r + q;
+ v = r->r + qm1;
+ b = bring[q];
+ a = bring[qm1];
+ print(" %0.4d %.2ux l=%d p=%#p @%#p\n", q, t->op,
+ (uint)gbit16(t->l), KZERO+(ulong)gbit32(t->status), Pciwaddrl(t));
+ print(" %0.4d %.2ux l=%d p=%#p @%#p\n", qm1, t->op,
+ (uint)gbit16(v->l), KZERO+(ulong)gbit32(v->status), Pciwaddrl(v));
+ if(r == &c->rx)
+ print(" %#p %#p (wp)\n", b? b->wp: 0, a? a->wp: 0);
+ else
+ print(" %#p %#p (rp)\n", b? b->rp: 0, a? a->rp: 0);
+
+ dumpring(r, bring, c->qno, p, f);
+ print(" %s", buf);
+}
|