]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etheryuk.c
etheryuk: fix lockups (thanks burnzez for testing)
[plan9front.git] / sys / src / 9 / pc / etheryuk.c
1 /*
2  * marvell 88e8057 yukon2
3  * copyright © 2009-10 erik quanstrom
4  */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "../port/error.h"
12 #include "../port/netif.h"
13 #include "etherif.h"
14
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 {}
19
20 extern  void    sfence(void);
21
22 enum {
23         Nctlr   = 4,
24         Nrb     = 1024,
25         Rbalign = 64,
26         Fprobe  = 1<<0,
27         Sringcnt        = 2048,
28         Tringcnt        = 512,
29         Rringcnt        = 512,
30         Rringl  = Rringcnt - 8,
31 };
32
33 enum {
34         /* pci registers */
35         Pciphy  = 0x40,
36         Pciclk  = 0x80,
37         Pciasp  = 0x84,
38         Pcistate        = 0x88,
39         Pcicf0  = 0x90,
40         Pcicf1  = 0x94,
41
42         /* “csr” registers */
43         Ctst    = 0x0004/2,             /* control and status */
44         Pwrctl  = 0x0007,               /* power control */
45         Isr     = 0x0008/4,             /* interrupt src */
46         Ism     = 0x000c/4,             /* interrupt mask */
47         Hwe     = 0x0010/4,             /* hw error */
48         Hwem    = 0x0014/4,             /* hw error mask*/
49         Isrc2   = 0x001c/4,
50         Eisr    = 0x0024/4,
51         Lisr    = 0x0028/4,             /* leave isr */
52         Icr     = 0x002c/4,
53         Macadr  = 0x0100,               /* mac address 2ports*3 */
54         Pmd     = 0x0119,
55         Maccfg  = 0x011a,
56         Chip    = 0x011b,
57         Ramcnt  = 0x011c,               /* # of 4k blocks */
58         Hres    = 0x011e,
59         Clkgate = 0x011d,
60         Clkctl  = 0x0120/4,
61         Tstctl1 = 0x0158,
62         Tstctl2 = 0x0159,
63         Gpio    = 0x015c/4,
64
65         Rictl   = 0x01a0,               /* ri ram buffer ctl */
66         Rib     = 0x0190,               /* ri buffer0 */
67
68         /* other unoffset registers */
69         Asfcs   = 0x0e68,               /* asf command and status */
70         Asfhost = 0x0e6c/4,
71
72         Statctl = 0x0e80/4,             /* status */
73         Stattl  = 0x0e84/2,             /* tail (previous) status addr */
74         Stataddr        = 0x0e88/4,             /* status address low */
75         Statth  = 0x0e98/2,
76         Stathd  = 0x0e9c/2,
77         Statwm  = 0x0eac,               /* stat watermark */
78         Statiwm = 0x0ead,               /* isr stat watermark */
79
80         Dpolltm = 0x0e08/4,             /* descriptor pool timer */
81
82         /* timers */
83         Tgv     = 0x0e14/4,             /* gmac timer current value */
84         Tgc     = 0x0e18,               /* gmac timer ctl */
85         Tgt     = 0x0e1a,               /* gmac timer test */
86
87         Tsti    = 0x0ec0/4,             /* stat tx timer ini */
88         Tlti    = 0x0eb0/4,             /* level */
89         Titi    = 0x0ed0/4,             /* isr */
90
91         Tstc    = 0x0ec8,               /* stat tx timer ctl */
92         Tltc    = 0x0eb8,               /* level timer ctl */
93         Titc    = 0x0ed8,               /* isr timer ctl */
94
95         /* “gmac” registers */
96         Stat    = 0x000/2,
97         Ctl     = 0x004/2,
98         Txctl   = 0x008/2,
99         Rxctl   = 0x00c/2,
100         Txflow  = 0x010/2,
101         Txparm  = 0x014/2,
102         Serctl  = 0x018/2,              /* serial mode */
103         Mchash  = 0x034/2,              /* 4 registers; 4 bytes apart */
104
105         /* interrupt sources and masks */
106         Txirq   = 0x044/2,
107         Rxirq   = 0x048/2,
108         Trirq   = 0x04c/2,              /* tx/rx overflow irq source */
109         Txmask  = 0x050/2,
110         Rxmask  = 0x054/2,
111         Trmask  = 0x058/2,
112
113         Smictl  = 0x080/2,              /* serial mode control */
114         Smidata = 0x084/2,
115         Phyaddr = 0x088/2,
116
117         Ea0     = 0x01c/2,              /* 3 16 bit gmac registers */
118         Ea1     = 0x028/2,
119
120         Stats   = 0x0100/4,
121
122         /* mac registers */
123         Txactl  = 0x210,                        /* transmit arbiter ctl */
124
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 */
133
134         Rxphi   = 0x0c58,               /* pause high watermark */
135         Rxplo   = 0x0c5c,               /* pause low watermark */
136
137         Rxwp    = 0x0c60/4,
138         Rxwlev  = 0x0c68/4,
139         Rxrp    = 0x0c70/4,
140         Rxrlev  = 0x0c78/4,
141
142         Mac     = 0x0f00/4,             /* global mac control */
143         Phy     = 0x0f04/4,             /* phy control register */
144
145         Irq     = 0x0f08,               /* irq source */
146         Irqm    = 0x0f0c,               /* irq mask */
147         Linkctl = 0x0f10,
148
149         /* queue registers; all offsets from Qbase*/
150         Qbase   = 0x0400,
151         Qportsz = 0x0080,               /* BOTCH; tx diff is 2x rx diff */
152
153         Qr      = 0x000,
154         Qtxs    = 0x200,
155         Qtx     = 0x280,
156
157         /* queue offsets */
158         Qd      = 0x00,
159         Qvlan   = 0x20,
160         Qdone   = 0x24,
161         Qaddrl  = 0x28,
162         Qaddrh  = 0x2c,
163         Qbc     = 0x30,
164         Qcsr    = 0x34,                 /* 32bit */
165         Qtest   = 0x38,
166         Qwm     = 0x40,
167
168         /* buffer registers; all offsets from Rbase */
169         Rbase   = 0x0800,
170
171         Rstart  = 0x00,
172         Rend    = 0x04,
173         Rwp     = 0x08,
174         Rrp     = 0x0c,
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 */
179         Rctl    = 0x28,
180
181         /* prefetch */
182         Pbase   = 0x450,
183         Pctl    = 0x00,
184         Plidx   = 0x04,                 /* last addr; 16 bit */
185         Paddrl  = 0x08,
186         Paddrh  = 0x0c,
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 */
192
193         /* indirect phy registers */
194         Phyctl  = 0x000,
195         Phystat = 0x001,
196         Phyid0  = 0x002,
197         Phyid1  = 0x003,
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 */
203         Gbectl  = 0x009,
204         Gbestat = 0x00a,
205         Phyphy  = 0x010,                        /* phy specific ctl */
206         Phylstat        = 0x011,
207         Phyintm = 0x012,                        /* phy interrupt mask */
208         Phyint  = 0x013,
209         Phyextctl       = 0x014,
210         Phyrxe  = 0x015,                        /* rx error counter */
211         Phypage = 0x016,                        /* external address */
212         Phypadr = 0x01d,                        /* phy page address */
213 };
214
215 enum {
216         /* Pciasp */
217         Aspforce                = 1<<15,
218         Aspglinkdn      = 1<<14,        /* gphy link down */
219         Aspfempty       = 1<<13,
220         Aspclkrun       = 1<<12,
221         Aspmsk          = Aspforce | Aspglinkdn | Aspfempty | Aspclkrun,
222
223         /* Pcistate */
224         Vmain           = 3<<27,
225
226         /* Stat */
227         Sfast           = 1<<15,        /* 100mbit */
228         Duplex          = 1<<14,
229         Txnofc          = 1<<13,        /* tx flow control disabled */
230         Link            = 1<<12,        /* link up */
231         Pausest         = 1<<11,        /* pause state */
232         Txactive                = 1<<10,
233         Excesscol       = 1<<9,
234         Latecol         = 1<<8,
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 */
239
240         /* Ctl */
241         Promiscen       = 1<<14,
242         Txfcdis         = 1<<13,
243         Txen            = 1<<12,
244         Rxen            = 1<<11,
245         Bursten         = 1<<10,
246         Loopen          = 1<<9,
247         Gbeen           = 1<<7,
248         Fpass           = 1<<6, /* "force link pass" ? */
249         Duplexen        = 1<<5,
250         Rxfcdis         = 1<<4,
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 */
255
256         /* Rxctl */
257         Ufilter         = 1<<15,        /* unicast filter */
258         Mfilter         = 1<<14,        /* multicast filter */
259         Rmcrc           = 1<<13,        /* remove frame crc */
260
261         /* Serctl */
262         Vlanen          = 1<<9,
263         Jumboen         = 1<<8,
264
265         /* Txactl */
266         Txaclr          = 1<<1,
267         Txarst          = 1<<0,
268
269         /* Asfcs: yukex only */
270         Asfbrrst                = 1<<9, /* bridge reset */
271         Asfcpurst       = 1<<8, /* cpu reset */
272         Asfucrst                = 3<<0, /* µctlr reset */
273
274         /* Asfcs */
275         Asfhvos         = 1<<4, /* os present */
276         Asfrst          = 1<<3,
277         Asfrun          = 1<<2,
278         Asfcirq         = 1<<1,
279         Afsirq          = 1<<0,
280
281         /* Statctl */
282         Statirqclr      = 1<<4,
283         Staton          = 1<<3,
284         Statoff         = 1<<2,
285         Statclr         = 1<<1,
286         Statrst         = 1<<0,
287
288         /* Mac */
289         Nomacsec        = 1<<13 | 1<<11,
290         Nortx           = 1<<9,
291         Macpause        = 1<<3,
292         Macpauseoff     = 1<<2,
293         Macrstclr       = 1<<1,
294         Macrst          = 1<<0,
295
296         /* Phy */
297         Gphyrstclr      = 1<<1,
298         Gphyrst         = 1<<0,
299
300         /* Irqm */
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 */
307
308         /* Linkctl */
309         Linkclr         = 1<<1,
310         Linkrst         = 1<<0,
311
312         /* Smictl */
313         Smiread         = 1<<5,
314         Smiwrite                = 0<<5,
315         Smirdone        = 1<<4,
316         Smibusy         = 1<<3,
317
318         /* Phyaddr */
319         Mibclear                = 1<<5,
320
321         /* Ctst */
322         Asfdis          = 1<<12,        /* asf disable */
323         Clken           = 1<<11,        /* enable clock */
324
325         Swirq           = 1<<7,
326         Swirqclr                = 1<<6,
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 */
331         Swclr           = 1<<1,
332         Swrst           = 1<<0,
333
334         /* Pwrctl */
335         Vauxen          = 1<<7,
336         Vauxdis         = 1<<6,
337         Vccen           = 1<<5,
338         Vccdis          = 1<<4,
339         Vauxon          = 1<<3,
340         Vauxoff         = 1<<2,
341         Vccon           = 1<<1,
342         Vccoff          = 1<<0,
343
344         /* timers */
345         Tstart          = 1<<2,
346         Tstop           = 1<<1,
347         Tclrirq         = 1<<0,
348
349         /* Dpolltm */
350         Pollstart               = 1<<1,
351         Pollstop                = 1<<0,
352
353         /* csr interrupts: Isrc2, Eisr, etc. */
354         Ihwerr          = 1<<31,
355         Ibmu            = 1<<30,        /* sring irq */
356         Isoftware       = 1<<25,
357
358         Iphy            = 1<<4,
359         Imac            = 1<<3,
360         Irx             = 1<<2,
361         Itxs            = 1<<1, /* descriptor error */
362         Itx             = 1<<0, /* descriptor error */
363
364         Iport           = 0x1f,
365         Iphy2base       = 8,
366         Ierror          = (Imac | Itx | Irx)*(1 | 1<<Iphy2base),
367
368         /* hwe interrupts: Hwe Hwem */
369         Htsof           = 1<<29,        /* timer stamp overflow */
370         Hsensor         = 1<<28,
371         Hmerr           = 1<<27,        /* master error */
372         Hstatus         = 1<<26,        /* status exception */
373         Hpcie           = 1<<25,        /* pcie error */
374         Hpcie2          = 1<<24,        /* " */
375
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 */
382
383         H1base          = 1<<0,
384         H2base          = 1<<8,
385         Hmask           = 0x3f,
386         Hdflt           = Htsof | Hmerr | Hstatus | Hmask*(H1base | H2base),
387
388         /* Clkctl */
389         Clkdiven                = 1<<1,
390         Clkdivdis       = 1<<0,
391
392         /* Clkgate */
393         Link2inactive   = 1<<7,
394
395         /* Phyctl */
396         Phyrst  = 1<<15,
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 */
401         Phydpx  = 1<<8,
402         Phy1000 = 1<<5,         /* manual enable gbe */
403
404         /* Phyana */
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 */
410         An100f  = 1<<8,
411         An100h  = 1<<7,
412         An10f   = 1<<6,
413         An10h   = 1<<5,
414         Anonly  = 1<<0,
415         Anall   = An100f | An100h | An10f | An10h | Anonly,
416
417         /* Gbectl */
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 */
422
423         /* Phyphy */
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 */
429
430         Ppengy  = 1<<14,                /* fe+ enable energy detect */
431         Ppscrdis        = 1<<9,         /* fe+ scrambler disable */
432         Ppnpe   = 1<<12,                /* fe+ enable next page */
433
434         /* Phylstat */
435         Physpd  = 3<<14,
436         Phydupx = 1<<13,
437         Phypr   = 1<<12,                /* page rx */
438         Phydone = 1<<11,                /* speed and duplex neg. done */
439         Plink   = 1<<10,
440         Pwirelen        = 7<<7,
441         Pmdi    = 1<<6,
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 */
448
449         /* Phyintm */
450         Anerr   = 1<<15,                /* an error */
451         Lsp     = 1<<14,                /* link speed change */
452         Andc    = 1<<13,                /* an duplex change */
453         Anok    = 1<<11,
454         Lsc     = 1<<10,                /* link status change */
455         Symerr  = 1<<9,         /* symbol error */
456         Fcarr   = 1<<8,         /* false carrier */
457         Fifoerr = 1<<7,
458         Mdich   = 1<<6,
459         Downsh  = 1<<5,
460         Engych  = 1<<4,         /* energy change */
461         Dtech   = 1<<2,         /* dte power det status */
462         Polch   = 1<<1,         /* polarity change */
463         Jabber  = 1<<0,
464
465         /* Phyextctl */
466         Dnmstr  = 1<<9,         /* master downshift; 0: 1x; 1: 2x; 2: 3x */
467         Dnslv   = 1<<8,
468
469         /* Tgc */
470         Tgstart = 1<<2,
471         Tgstop  = 1<<1,
472         Tgclr   = 1<<0,         /* clear irq */
473
474         /* Tstctl1 */
475         Tstwen  = 1<<1,         /* enable config reg r/w */
476         Tstwdis = 1<<0,         /* disable config reg r/w */
477
478         /* Gpio */
479         Norace  = 1<<13,
480
481         /* Rictl */
482         Rirpclr = 1<<9,
483         Riwpclr = 1<<8,
484         Riclr   = 1<<1,
485         Rirst   = 1<<0,
486
487         /* Rbase opcodes */
488         Rsfon   = 1<<5,         /* enable store/fwd */
489         Rsfoff  = 1<<4,
490         Renable = 1<<3,
491         Rdisable        = 1<<2,
492         Rrstclr = 1<<1,
493         Rrst    = 1<<0,
494
495         /* Qbase opcodes */
496         Qidle   = 1<<31,
497         Qtcprx  = 1<<30,
498         Qiprx   = 1<<29,
499         Qrssen  = 1<<15,
500         Qrssdis = 1<<14,
501         Qsumen  = 1<<13,                /* tcp/ip cksum */
502         Qsumdis = 1<<12,
503         Qcirqpar        = 1<<11,                /* clear irq on parity errors */
504         Qcirqck = 1<<10,
505         Qstop   = 1<<9,
506         Qstart  = 1<<8,
507         Qfifoon = 1<<7,
508         Qfifooff        = 1<<6,
509         Qfifoen = 1<<5,
510         Qfiforst        = 1<<4,
511         Qenable = 1<<3,
512         Qdisable        = 1<<2,
513         Qrstclr = 1<<1,
514         Qrst    = 1<<0,
515
516         Qallclr = Qfiforst | Qfifooff | Qrstclr,
517         Qgo     = Qcirqpar | Qcirqck | Qstart | Qfifoen | Qenable,
518
519         /* Qtest bits */
520         Qckoff  = 1<<31,                /* tx: auto checksum off */
521         Qckon   = 1<<30,
522         Qramdis = 1<<24,                /* rx: ram disable */
523
524         /* Pbase opcodes */
525         Prefon  = 1<<3,         /* prefetch on */
526         Prefoff = 1<<2,
527         Prefrstclr      = 1<<1,
528         Prefrst = 1<<0,
529
530         /* ring opcodes */
531         Hw      = 0x80,                 /* bitmask */
532         Ock     = 0x12,                 /* tcp checksum start */
533         Oaddr64 = 0x21,
534         Obuf    = 0x40,
535         Opkt    = 0x41,
536         Orxstat = 0x60,
537         Orxts   = 0x61,                 /* rx timestamp */
538         Orxvlan = 0x62,
539         Orxchks = 0x64,
540         Otxidx  = 0x68,
541         Omacs   = 0x6c,                 /* macsec */
542         Oputidx = 0x70,
543
544         /* ring status */
545         Eop     = 0x80,
546
547         /* Gfrxctl */
548         Gftrunc = 1<<27,
549         Gftroff = 1<<26,
550
551         Gfroon  = 1<<19,        /* flush on rx overrun */
552         Gfrooff = 1<<18,
553         Gffon   = 1<<7, /* rx fifo flush mode on */
554         Gffoff  = 1<<6,
555         Gfon    = 1<<3,
556         Gfoff   = 1<<2,
557         Gfrstclr        = 1<<1,
558         Gfrst   = 1<<0,
559
560         /* Gmfctl */
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 */
570         Gmfon   = 1<<3,
571         Gmfoff  = 1<<2,
572         Gmfclr  = 1<<1,
573         Gmfrst  = 1<<0,
574
575         /* rx frame */
576         Flen    = 0x7fff<<17,
577         Fvlan   = 1<<13,
578         Fjabbr  = 1<<12,
579         Ftoosm  = 1<<11,
580         Fmc     = 1<<10,        /* multicast */
581         Fbc     = 1<<9,
582         Fok     = 1<<8, /* good frame */
583         Fokfc   = 1<<7,
584         Fbadfc  = 1<<6,
585         Fmiierr = 1<<5,
586         Ftoobg  = 1<<4, /* oversized */
587         Ffrag   = 1<<3, /* fragment */
588         Fcrcerr = 1<<1,
589         Ffifoof = 1<<0, /* fifo overflow */
590         Ferror  = Ffifoof | Fcrcerr | Ffrag | Ftoobg
591                 | Fmiierr | Fbadfc | Ftoosm | Fjabbr,
592
593         /* rx checksum bits in Status.ctl */
594         Badck   = 5,            /* arbitrary bad checksum */
595
596         Ctcpok  = 1<<7, /* tcp or udp cksum ok */
597         Cisip6  = 1<<3,
598         Cisip4  = 1<<1,
599
600         /* more status ring rx bits */
601         Rxvlan  = 1<<13,
602         Rxjab   = 1<<12,        /* jabber */
603         Rxsmall = 1<<11,        /* too small */
604         Rxmc    = 1<<10,        /* multicast */
605         Rxbc    = 1<<9, /* bcast */
606         Rxok    = 1<<8,
607         Rxfcok  = 1<<7, /* flow control pkt */
608         Rxfcbad = 1<<6,
609         Rxmiierr        = 1<<5,
610         Rxbig   = 1<<4, /* too big */
611         Rxfrag  = 1<<3,
612         Rxcrcerr        = 1<<1,
613         Rxfov   = 1<<0, /* fifo overflow */
614         Rxerror = Rxfov | Rxcrcerr | Rxfrag | Rxbig | Rxmiierr
615                 | Rxfcbad | Rxsmall | Rxjab,
616 };
617
618 enum {
619         Ffiber  = 1<<0,
620         Fgbe    = 1<<1,
621         Fnewphy = 1<<2,
622         Fapwr   = 1<<3,
623         Fnewle  = 1<<4,
624         Fram    = 1<<5,
625         Fancy   =Fgbe | Fnewphy | Fapwr,
626
627         Yukxl   = 0,
628         Yukecu,
629         Yukex,
630         Yukec,
631         Yukfe,
632         Yukfep,
633         Yuksup,
634         Yukul2,
635         Yukba,          /* doesn't exist */
636         Yukopt,
637         Nyuk,
638 };
639
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;
649
650 struct Chipid {
651         uchar   feat;
652         uchar   okrev;
653         uchar   mhz;
654         char    *name;
655 };
656
657 struct Kproc {
658         Rendez;
659         uint    event;
660 };
661
662 struct Sring {
663         uint    wp;
664         uint    rp;
665         uint    cnt;
666         uint    m;
667         Status  *r;
668 };
669
670 struct Ctlr {
671         Pcidev  *p;
672         Ctlr    *oport;         /* port 2 */
673         uchar   qno;
674         uchar   attach;
675         uchar   rxinit;
676         uchar   txinit;
677         uchar   flag;
678         uchar   feat;
679         uchar   type;
680         uchar   rev;
681         uchar   nports;
682         uchar   portno;
683         uintptr io;
684         uchar   *reg8;
685         ushort  *reg16;
686         uint    *reg;
687         uint    rbsz;
688         uchar   ra[Eaddrlen];
689         uint    mca;
690         uint    nmc;
691         Mc      *mc;
692         void    *alloc;
693         Sring   status;
694         Sring   tx;
695         Block   *tbring[Tringcnt];
696         Sring   rx;
697         Block   *rbring[Rringcnt];
698         Kproc   txmit;
699         Kproc   rxmit;
700         Kproc   iproc;
701 };
702
703 struct Mc {
704         Mc      *next;
705         uchar   ea[Eaddrlen];
706 };
707
708 struct Stattab {
709         uint    offset;
710         char    *name;
711 };
712
713 struct Status {
714         uchar   status[4];
715         uchar   l[2];
716         uchar   ctl;
717         uchar   op;
718 };
719
720 struct Vtab {
721         int     vid;
722         int     did;
723         int     mtu;
724         char    *name;
725 };
726
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",
738 };
739
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",
749 };
750
751 static Stattab stattab[] = {
752         0,      "rx ucast",
753         8,      "rx bcast",
754         16,     "rx pause",
755         24,     "rx mcast",
756         32,     "rx chk seq",
757
758         48,     "rx ok low",
759         56,     "rx ok high",
760         64,     "rx bad low",
761         72,     "rx bad high",
762
763         80,     "rx frames < 64",
764         88,     "rx frames < 64 fcs",
765         96,     "rx frames 64",
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",
773         160,    "rx jabber",
774         176,    "rx fifo oflow",
775
776         192,    "tx ucast",
777         200,    "tx bcast",
778         208,    "tx pause",
779         216,    "tx mcast",
780
781         224,    "tx ok low",
782         232,    "tx ok hi",
783
784         240,    "tx frames 64",
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",
791
792         304,    "tx coll",
793         312,    "tx late coll",
794         320,    "tx excess coll",
795         328,    "tx mul col",
796         336,    "tx single col",
797         344,    "tx underrun",
798 };
799
800 static  uint    phypwr[] = {1<<26, 1<<27};
801 static  uint    coma[] = {1<<28, 1<<29};
802 static  uchar   nilea[Eaddrlen];
803 static  int     debug;
804 static  Ctlr    *ctlrtab[Nctlr];
805 static  int     nctlr;
806
807 static int
808 icansleep(void *v)
809 {
810         Kproc *k;
811
812         k = v;
813         return k->event != 0;
814 }
815
816 static void
817 unstarve(Kproc *k)
818 {
819         k->event = 1;
820         wakeup(k);
821 }
822
823 static void
824 starve(Kproc *k)
825 {
826         sleep(k, icansleep, k);
827         k->event = 0;
828 }
829
830 static int
831 getnslot(Sring *r, uint *wp, Status **t, uint n)
832 {
833         int i;
834
835         if(r->m - (int)(wp[0] - r->rp) < n)
836                 return -1;
837         for(i = 0; i < n; i++)
838                 t[i] = r->r + (wp[0]++ & r->m);
839         return 0;
840 }
841
842 static uint
843 macread32(Ctlr *c, uint r)
844 {
845         return c->reg[c->portno*0x20 + r];
846 }
847
848 static void
849 macwrite32(Ctlr *c, uint r, uint v)
850 {
851         c->reg[c->portno*0x20 + r] = v;
852 }
853
854 static uint
855 macread16(Ctlr *c, uint r)
856 {
857         return c->reg16[c->portno*0x40 + r];
858 }
859
860 static void
861 macwrite16(Ctlr *c, uint r, uint v)
862 {
863         c->reg16[c->portno*0x40 + r] = v;
864 }
865
866 static uint
867 macread8(Ctlr *c, uint r)
868 {
869         return c->reg8[c->portno*0x80 + r];
870 }
871
872 static void
873 macwrite8(Ctlr *c, uint r, uint v)
874 {
875         c->reg8[c->portno*0x80 + r] = v;
876 }
877
878 static uint gmac32[2] = {
879         0x2800/4,
880         0x3800/4,
881 };
882
883 static ushort
884 gmacread32(Ctlr *c, uint r)
885 {
886         return c->reg[gmac32[c->portno] + r];
887 }
888
889 static void
890 gmacwrite32(Ctlr *c, uint r, uint v)
891 {
892         c->reg[gmac32[c->portno] + r] = v;
893 }
894
895 static uint gmac[2] = {
896         0x2800/2,
897         0x3800/2,
898 };
899
900 static ushort
901 gmacread(Ctlr *c, uint r)
902 {
903         return c->reg16[gmac[c->portno] + r];
904 }
905
906 static void
907 gmacwrite(Ctlr *c, uint r, ushort v)
908 {
909         c->reg16[gmac[c->portno] + r] = v;
910 }
911
912 static uint
913 qrread(Ctlr *c, uint r)
914 {
915         return c->reg[Qbase + c->portno*Qportsz + r>>2];
916 }
917
918 static void
919 qrwrite(Ctlr *c, uint r, uint v)
920 {
921         c->reg[Qbase + c->portno*Qportsz + r>>2] = v;
922 }
923
924 static uint
925 qrread16(Ctlr *c, uint r)
926 {
927         return c->reg16[Qbase + c->portno*Qportsz + r>>1];
928 }
929
930 static void
931 qrwrite16(Ctlr *c, uint r, uint v)
932 {
933         c->reg16[Qbase + c->portno*Qportsz + r>>1] = v;
934 }
935
936 static uint
937 qrread8(Ctlr *c, uint r)
938 {
939         return c->reg8[Qbase + c->portno*Qportsz + r>>0];
940 }
941
942 static void
943 qrwrite8(Ctlr *c, uint r, uint v)
944 {
945         c->reg8[Qbase + c->portno*Qportsz + r>>0] = v;
946 }
947
948 static uint
949 rrread32(Ctlr *c, uint r)
950 {
951         return c->reg[Rbase + c->portno*Qportsz + r>>2];
952 }
953
954 static void
955 rrwrite32(Ctlr *c, uint r, uint v)
956 {
957         c->reg[Rbase + c->portno*Qportsz + r>>2] = v;
958 }
959
960 static void
961 rrwrite8(Ctlr *c, uint r, uint v)
962 {
963         c->reg8[Rbase + c->portno*Qportsz + r] = v;
964 }
965
966 static uint
967 rrread8(Ctlr *c, uint r)
968 {
969         return c->reg8[Rbase + c->portno*Qportsz + r];
970 }
971
972 static uint
973 prread32(Ctlr *c, uint r)
974 {
975         return c->reg[Pbase + c->portno*Qportsz + r>>2];
976 }
977
978 static void
979 prwrite32(Ctlr *c, uint r, uint v)
980 {
981         c->reg[Pbase + c->portno*Qportsz + r>>2] = v;
982 }
983
984 static uint
985 prread16(Ctlr *c, uint r)
986 {
987         return c->reg16[Pbase + c->portno*Qportsz + r>>1];
988 }
989
990 static void
991 prwrite16(Ctlr *c, uint r, uint v)
992 {
993         c->reg16[Pbase + c->portno*Qportsz + r>>1] = v;
994 }
995
996 static ushort
997 phyread(Ctlr *c, uint r)
998 {
999         ushort v;
1000
1001         gmacwrite(c, Smictl, Smiread | r<<6);
1002         for(;;){
1003                 v = gmacread(c, Smictl);
1004                 if(v == 0xffff)
1005                         error("phy read");
1006                 if(v & Smirdone)
1007                         return gmacread(c, Smidata);
1008                 microdelay(10);
1009         }
1010 }
1011
1012 static ushort
1013 phywrite(Ctlr *c, uint r, ushort v)
1014 {
1015         gmacwrite(c, Smidata, v);
1016         gmacwrite(c, Smictl, Smiwrite | r<<6);
1017         for(;;){
1018                 v = gmacread(c, Smictl);
1019                 if(v == 0xffff)
1020                         error("phy write");
1021                 if((v & Smibusy) == 0)
1022                         return gmacread(c, Smidata);
1023                 microdelay(10);
1024         }
1025 }
1026
1027 static uvlong lorder = 0x0706050403020100ull;
1028
1029 static uvlong
1030 getle(uchar *t, int w)
1031 {
1032         uint i;
1033         uvlong r;
1034
1035         r = 0;
1036         for(i = w; i != 0; )
1037                 r = r<<8 | t[--i];
1038         return r;
1039 }
1040
1041 static void
1042 putle(uchar *t, uvlong r, int w)
1043 {
1044         uchar *o, *f;
1045         uint i;
1046
1047         f = (uchar*)&r;
1048         o = (uchar*)&lorder;
1049         for(i = 0; i < w; i++)
1050                 t[o[i]] = f[i];
1051 }
1052
1053 static void
1054 bufinit(Ctlr *c, uint q, uint start, uint end)
1055 {
1056         uint t;
1057
1058         rrwrite8(c, q + Rctl, Rrstclr);
1059         rrwrite32(c, q + Rstart, start);
1060         rrwrite32(c, q + Rend, end-1);
1061         rrwrite32(c, q + Rwp, start);
1062         rrwrite32(c, q + Rrp, start);
1063
1064         if(q == Qr || q == Qr + Qportsz){
1065                 t = start-end;
1066                 rrwrite32(c, q + Rpon, t - 8192/8);
1067                 rrwrite32(c, q + Rpoff, t - 16384/8);
1068         } else
1069                 rrwrite8(c, q + Rctl, Rsfon);
1070         rrwrite8(c, q + Rctl, Renable);
1071         rrread8(c, q + Rctl);
1072 }
1073
1074 static void
1075 qinit(Ctlr *c, uint queue)
1076 {
1077         qrwrite(c, queue + Qcsr, Qallclr);
1078         qrwrite(c, queue + Qcsr, Qgo);
1079         qrwrite(c, queue + Qcsr, Qfifoon);
1080         qrwrite16(c, queue + Qwm,  0x600);              /* magic */
1081 //      qrwrite16(c, queue + Qwm,  0x80);               /* pcie magic; assume pcie; no help */
1082 }
1083
1084 /* initialized prefetching */
1085 static void
1086 pinit(Ctlr *c, uint queue, Sring *r)
1087 {
1088         union {
1089                 uchar   u[4];
1090                 uint    l;
1091         } u;
1092
1093         prwrite32(c, queue + Pctl, Prefrst);
1094         prwrite32(c, queue + Pctl, Prefrstclr);
1095         putle(u.u, Pciwaddrh(r->r), 4);
1096         prwrite32(c, queue + Paddrh, u.l);
1097         putle(u.u, Pciwaddrl(r->r), 4);
1098         prwrite32(c, queue + Paddrl, u.l);
1099         prwrite16(c, queue + Plidx, r->m);
1100         prwrite32(c, queue + Pctl, Prefon);
1101         prread32(c, queue + Pctl);
1102 }
1103
1104 static void
1105 txinit(Ether *e)
1106 {
1107         Ctlr *c;
1108         Sring *r;
1109
1110         c = e->ctlr;
1111         r = &c->tx;
1112         if(c->txinit == 1)
1113                 return;
1114         c->txinit = 1;
1115         r->wp = 0;
1116         r->rp = 0;
1117         qinit(c, Qtx);
1118         pinit(c,  Qtx, &c->tx);
1119 }
1120
1121 static void
1122 linkup(Ctlr *c, uint w)
1123 {
1124         static Lock l;
1125
1126         lock(&l);
1127         gmacwrite(c, Ctl, w|gmacread(c, Ctl));
1128         unlock(&l);
1129 }
1130
1131 static void
1132 tproc(void *v)
1133 {
1134         Block *b;
1135         Ctlr *c;
1136         Ether *e;
1137         Sring *r;
1138         Status *tab[2], *t;
1139
1140         e = v;
1141         c = e->ctlr;
1142         r = &c->tx;
1143
1144         txinit(e);
1145         linkup(c, Txen);
1146         while(waserror())
1147                 ;
1148         for(;;){
1149                 if((b = qbread(e->oq, 100000)) == nil)
1150                         break;
1151                 while(getnslot(r, &r->wp, tab, 1 + is64()) == -1)
1152                         starve(&c->txmit);
1153                 t = tab[is64()];
1154                 c->tbring[t - r->r] = b;
1155                 if(is64()){
1156                         Status *t = tab[0];
1157                         t->ctl = 0;
1158                         t->op = Oaddr64 | Hw;
1159                         putle(t->status, Pciwaddrh(b->rp), 4);
1160                 }
1161                 putle(t->status, Pciwaddrl(b->rp), 4);
1162                 putle(t->l, BLEN(b), 2);
1163                 t->op = Opkt | Hw;
1164                 t->ctl = Eop;
1165                 sfence();
1166                 prwrite16(c, Qtx + Pputidx, r->wp & r->m);
1167         }
1168         print("#l%d: tproc: queue closed\n", e->ctlrno);
1169         pexit("queue closed", 1);
1170 }
1171
1172 static void
1173 rxinit(Ether *e)
1174 {
1175         Ctlr *c;
1176         Sring *r;
1177         Status *t;
1178
1179         c = e->ctlr;
1180         r = &c->rx;
1181         if(c->rxinit == 1)
1182                 return;
1183         c->rxinit = 1;
1184         qinit(c, Qr);
1185         if(c->type == Yukecu && (c->rev == 2 || c->rev == 3))
1186                 qrwrite(c, Qr + Qtest, Qramdis);
1187         pinit(c,  Qr, &c->rx);
1188
1189         if((c->flag & Fnewle) == 0){
1190                 while(getnslot(r, &r->wp, &t, 1) == -1)
1191                         starve(&c->rxmit);
1192                 putle(t->status, 14<<16 | 14, 4);
1193                 t->ctl = 0;
1194                 t->op = Ock | Hw;
1195                 qrwrite(c, Qr + Qcsr, Qsumen);
1196         }
1197         macwrite32(c, Gfrxctl, Gftroff);
1198 }
1199
1200 /* debug; remove */
1201 #include "yukdump.h"
1202 static int
1203 rxscrew(Ether *e, Sring *r, Status *t, uint wp)
1204 {
1205         Ctlr *c;
1206
1207         c = e->ctlr;
1208         if((int)(wp - r->rp) >= r->cnt){
1209                 print("rxscrew1 wp %ud(%ud) rp %ud %lud\n", wp, r->wp, r->rp, t-r->r);
1210                 return -1;
1211         }
1212         if(c->rbring[t - r->r]){
1213                 print("rxscrew2 wp %ud rp %ud %lud\n", wp, r->rp, t-r->r);
1214                 descriptorfu(e, Qr);
1215                 return -1;
1216         }
1217         return 0;
1218 }
1219
1220 static int
1221 replenish(Ether *e, Ctlr *c)
1222 {
1223         int n, lim;
1224         uint wp;
1225         Block *b;
1226         Sring *r;
1227         Status *tab[2], *t;
1228
1229         r = &c->rx;
1230         wp = r->wp;
1231
1232         lim = r->cnt/2;
1233         if(lim > 128)
1234                 lim = 128;              /* hw limit? */
1235         for(n = 0; n < lim; n++){
1236                 b = iallocb(c->rbsz + Rbalign);
1237                 if(b == nil || getnslot(r, &wp, tab, 1 + is64()) == -1){
1238                         freeb(b);
1239                         break;
1240                 }
1241                 b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, Rbalign);
1242
1243                 t = tab[is64()];
1244                 if(rxscrew(e, r, t, wp) == -1){
1245                         freeb(b);
1246                         break;
1247                 }
1248                 c->rbring[t - r->r] = b;
1249
1250                 if(is64()){
1251                         Status *t = tab[0];
1252                         putle(t->status, Pciwaddrh(b->wp), 4);
1253                         t->ctl = 0;
1254                         t->op = Oaddr64 | Hw;
1255                 }
1256                 putle(t->status, Pciwaddrl(b->wp), 4);
1257                 putle(t->l, c->rbsz, 2);
1258                 t->ctl = 0;
1259                 t->op = Opkt | Hw;
1260         }
1261         if(n>0){
1262                 r->wp = wp;
1263                 sfence();
1264                 prwrite16(c, Qr + Pputidx, wp & r->m);
1265                 dprint("yuk: replenish %d %ud-%ud [%d-%d]\n", n, r->rp, wp, r->rp&r->m, wp&r->m);
1266         }
1267         return n == lim;
1268 }
1269
1270 static void
1271 rproc(void *v)
1272 {
1273         Ctlr *c;
1274         Ether *e;
1275
1276         e = v;
1277         c = e->ctlr;
1278
1279         rxinit(e);
1280         linkup(c, Rxen);
1281         while(waserror())
1282                 ;
1283         for(;;){
1284                 if(replenish(e, c) == 0)
1285                         starve(&c->rxmit);
1286         }
1287 }
1288
1289 static void
1290 promiscuous(void *a, int on)
1291 {
1292         uint r;
1293         Ether *e;
1294         Ctlr *c;
1295
1296         e = a;
1297         c = e->ctlr;
1298         r = gmacread(c, Rxctl);
1299         if(on)
1300                 r &= ~(Ufilter|Mfilter);
1301         else
1302                 r |= Ufilter|Mfilter;
1303         gmacwrite(c, Rxctl, r);
1304 }
1305
1306 static uchar pauseea[] = {1, 0x80, 0xc2, 0, 0, 1};
1307
1308 static void
1309 multicast(void *a, uchar *ea, int on)
1310 {
1311         uchar f[8];
1312         uint i, r, b;
1313         Ctlr *c;
1314         Ether *e;
1315         Mc **ll, *l, *p;
1316
1317         e = a;
1318         c = e->ctlr;
1319         r = gmacread(c, Rxctl);
1320         if(on){
1321                 for(ll = &c->mc; *ll != nil; ll = &(*ll)->next)
1322                         if(memcmp((*ll)->ea, ea, Eaddrlen) == 0)
1323                                 return;
1324                 *ll = malloc(sizeof **ll);
1325                 memmove((*ll)->ea, ea, Eaddrlen);
1326         }else{
1327                 for(p = nil, l = c->mc; l != nil; p = l, l = l->next)
1328                         if(memcmp(l->ea, ea, Eaddrlen) == 0)
1329                                 break;
1330                 if(l == nil)
1331                         return;
1332                 if(p != nil)
1333                         p->next = l->next;
1334                 else
1335                         c->mc = l->next;
1336                 free(l);
1337         }
1338         memset(f, 0, sizeof f);
1339         if(0 /* flow control */){
1340                 b = ethercrc(pauseea, Eaddrlen) & 0x3f;
1341                 f[b>>3] |= 1 << (b & 7);
1342         }
1343         for(l = c->mc; l != nil; l = l->next){
1344                 b = ethercrc(l->ea, Eaddrlen) & 0x3f;
1345                 f[b>>3] |= 1 << (b & 7);
1346         }
1347         for(i = 0; i < sizeof f / 2; i++)
1348                 gmacwrite(c, Mchash + 2*i, f[i] | f[i+1]<<8);
1349         gmacwrite(c, Rxctl, r | Mfilter);
1350 }
1351
1352 static int spdtab[4] = {
1353         10, 100, 1000, 0,
1354 };
1355
1356 static void
1357 link(Ether *e)
1358 {
1359         uint i, s, spd;
1360         Ctlr *c;
1361
1362         c = e->ctlr;
1363         i = phyread(c, Phyint);
1364         s = phyread(c, Phylstat);
1365         dprint("#l%d: yuk: link %.8ux %.8ux\n", e->ctlrno, i, s);
1366         spd = 0;
1367         e->link = (s & Plink) != 0;
1368         if(e->link && c->feat&Ffiber)
1369                 spd = 1000;
1370         else if(e->link){
1371                 spd = s & Physpd;
1372                 spd >>= 14;
1373                 spd = spdtab[spd];
1374         }
1375         e->mbps = spd;
1376         dprint("#l%d: yuk: link %d spd %d\n", e->ctlrno, e->link, e->mbps);
1377 }
1378
1379 static void
1380 txcleanup(Ctlr *c, uint end)
1381 {
1382         uint rp;
1383         Block *b;
1384         Sring *r;
1385         Status *t;
1386
1387         r = &c->tx;
1388         end &= r->m;
1389         for(rp = r->rp & r->m; rp != end; rp = r->rp & r->m){
1390                 t = r->r + rp;
1391                 r->rp++;
1392                 if((t->ctl & Eop) == 0)
1393                         continue;
1394                 b = c->tbring[rp];
1395                 c->tbring[rp] = nil;
1396                 if(b != nil)
1397                         freeb(b);
1398         }
1399         unstarve(&c->txmit);
1400 }
1401
1402 static void
1403 rx(Ether *e, uint l, uint x, uint flag)
1404 {
1405         uint cnt, i, rp;
1406         Block *b;
1407         Ctlr *c;
1408         Sring *r;
1409
1410         c = e->ctlr;
1411         r = &c->rx;
1412         for(rp = r->rp;;){
1413                 if(rp == r->wp){
1414                         print("#l%d: yuk rx empty\n", e->ctlrno);
1415                         return;
1416                 }
1417                 i = rp++&r->m;
1418                 b = c->rbring[i];
1419                 c->rbring[i] = nil;
1420                 if(b != nil)
1421                         break;
1422         }
1423         r->rp = rp;
1424         cnt = x>>16 & 0x7fff;
1425         if((cnt != l || x&Rxerror) &&
1426         !(c->type == Yukfep && c->rev == 0)){
1427                 print("#l%d: yuk rx error %.4ux\n", e->ctlrno, x&0xffff);
1428                 freeb(b);
1429         }else{
1430                 b->wp += l;
1431                 b->flag |= flag;
1432                 etheriq(e, b, 1);
1433         }
1434         unstarve(&c->rxmit);
1435 }
1436
1437 static uint
1438 cksum(Ctlr *c, uint ck, uint css)
1439 {
1440         if(c->flag & Fnewle && css&(Cisip4|Cisip6) && css&Ctcpok)
1441                 return Bipck | Btcpck | Budpck;
1442         else if(ck == 0xffff || ck == 0)
1443                 return Bipck;
1444         return 0;
1445 }
1446
1447 static void
1448 sring(Ether *e)
1449 {
1450         uint i, lim, op, l, x;
1451         Ctlr *c;
1452         Sring *r;
1453         Status *s;
1454         static uint ck = Badck;
1455
1456         c = e->ctlr;
1457         r = &c->status;
1458         lim = c->reg16[Stathd] & r->m;
1459         for(;;){
1460                 i = r->rp & r->m;
1461                 if(i == lim){
1462                         lim = c->reg16[Stathd] & r->m;
1463                         if(i == lim)
1464                                 break;
1465                 }
1466                 s = r->r + i;
1467                 op = s->op;
1468                 if((op & Hw) == 0)
1469                         break;
1470                 op &= ~Hw;
1471                 switch(op){
1472                 case Orxchks:
1473                         ck = getle(s->status, 4) & 0xffff;
1474                         break;
1475                 case Orxstat:
1476                         l = getle(s->l, 2);
1477                         x = getle(s->status, 4);
1478                         rx(e, l, x, cksum(c, ck, s->ctl));
1479                         ck = Badck;
1480                         break;
1481                 case Otxidx:
1482                         l = getle(s->l, 2);
1483                         x = getle(s->status, 4);
1484                         txcleanup(c, x & 0xfff);
1485
1486                         x = l>>24 & 0xff | l<< 8;
1487                         x &= 0xfff;
1488                         if(x != 0 && c->oport)
1489                                 txcleanup(c->oport, x);
1490                         break;
1491                 default:
1492                         print("#l%d: yuk: funny opcode %.2ux\n", e->ctlrno, op);
1493                         break;
1494                 }
1495                 s->op = 0;
1496                 r->rp++;
1497         }
1498         c->reg[Statctl] = Statirqclr;
1499 }
1500
1501 enum {
1502         Pciaer  = 0x1d00,
1503         Pciunc  = 0x0004,
1504 };
1505
1506 static void
1507 hwerror(Ether *e, uint cause)
1508 {
1509         uint u;
1510         Ctlr *c;
1511
1512         c = e->ctlr;
1513         cause = c->reg[Hwe];
1514         if(cause == 0)
1515                 print("hwe: no cause\n");
1516         if(cause & Htsof){
1517                 c->reg8[Tgc] = Tgclr;
1518                 cause &= ~Htsof;
1519         }
1520         if(cause & (Hmerr | Hstatus)){
1521                 c->reg8[Tstctl1] = Tstwen;
1522                 u = pcicfgr16(c->p, PciPSR) | 0x7800;
1523                 pcicfgw16(c->p, PciPSR, u);
1524                 c->reg8[Tstctl1] = Tstwdis;
1525                 cause &= ~(Hmerr | Hstatus);
1526         }
1527         if(cause & Hpcie){
1528                 c->reg8[Tstctl1] = Tstwen;
1529                 c->reg[Pciaer + Pciunc>>2] = ~0;
1530                 u =  c->reg[Pciaer + Pciunc>>2];
1531                 USED(u);
1532                 print("#l%d: pcierror %.8ux\n", e->ctlrno, u);
1533                 c->reg8[Tstctl1] = Tstwdis;
1534                 cause &= ~Hpcie;
1535         }
1536         if(cause & Hrxparity){
1537                 print("#l%d: ram parity read error.  bug? ca %.8ux\n", e->ctlrno, cause);
1538                 qrwrite(c, Qtx + Qcsr, Qcirqpar);
1539                 cause &= ~Hrxparity;
1540         }
1541         if(cause & Hrparity){
1542                 print("#l%d: ram parity read error.  bug? ca %.8ux\n", e->ctlrno, cause);
1543                 descriptorfu(e, Qr);
1544                 descriptorfu(e, Qtx);
1545                 c->reg16[Rictl + c->portno*0x40>>1] = Rirpclr;
1546                 cause &= ~Hrparity;
1547         }
1548         if(cause & Hwparity){
1549                 print("#l%d: ram parity write error.  bug? ca %.8ux\n", e->ctlrno, cause);
1550                 descriptorfu(e, Qr);
1551                 descriptorfu(e, Qtx);
1552                 c->reg16[Rictl + c->portno*0x40>>1] = Riwpclr;
1553                 cause &= ~Hwparity;
1554         }
1555         if(cause & Hmfault){
1556                 print("#l%d: mac parity error\n", e->ctlrno);
1557                 macwrite32(c, Gmfctl, Gmfcpe);
1558                 cause &= ~Hmfault;
1559         }
1560         if(cause)
1561                 print("#l%d: leftover hwe %.8ux\n", e->ctlrno, cause);
1562 }
1563
1564 static void
1565 macintr(Ether *e)
1566 {
1567         uint cause;
1568         Ctlr *c;
1569
1570         c = e->ctlr;
1571         cause = macread8(c, Irq);
1572         cause  &= ~(Rxdone | Txdone);
1573         if(cause == 0)
1574                 return;
1575         print("#l%d: mac error %.8ux\n", e->ctlrno, cause);
1576         if(cause & Txovfl){
1577                 gmacread32(c, Txirq);
1578                 cause &= ~Txovfl;
1579         }
1580         if(cause & Rxovfl){
1581                 gmacread32(c, Rxirq);
1582                 cause &= ~Rxovfl;
1583         }
1584         if(cause & Rxorun){
1585                 macwrite32(c, Gfrxctl, Gmfcfu);
1586                 cause &= ~Rxorun;
1587         }
1588         if(cause & Txurun){
1589                 macwrite32(c, Gmfctl, Gmfcfu);
1590                 cause &= ~Txurun;
1591         }
1592         if(cause)
1593                 print("#l%d: leftover mac error %.8ux\n", e->ctlrno, cause);
1594 }
1595
1596 static struct {
1597         uint    i;
1598         uint    q;
1599         char    *s;
1600 } emap[] = {
1601         Irx,            Qr,             "qr",
1602         Itxs,           Qtxs,           "qtxs",
1603         Itx,            Qtx,            "qtx",
1604         Irx<<Iphy2base, Qr + 0x80,      "qr1",
1605         Itxs<<Iphy2base,        Qtxs + 0x100,   "qtxs1",
1606         Itx<<Iphy2base, Qtx + 0x100,    "qtx1",
1607 };
1608
1609 static void
1610 eerror(Ether *e, uint cause)
1611 {
1612         uint i, o, q;
1613         Ctlr *c;
1614
1615         c = e->ctlr;
1616
1617         if(cause & Imac){
1618                 macintr(e);
1619                 cause &= ~Imac;
1620         }
1621         if(cause & (Irx | Itxs | Itx)*(1 | 1<<Iphy2base))
1622                 for(i = 0; i < nelem(emap); i++){
1623                         if((cause & emap[i].i) == 0)
1624                                 continue;
1625                         q = emap[i].q;
1626                         o = prread16(c, q + Pgetidx);
1627                         print("#l%d: yuk: bug: %s: @%d ca=%.8ux\n", 
1628                                 e->ctlrno, emap[i].s, o, cause);
1629                         descriptorfu(e, q);
1630                         qrwrite(c, emap[i].q + Qcsr, Qcirqck);
1631                         cause &= ~emap[i].i;
1632                 }
1633         if(cause)
1634                 print("#l%d: leftover error %.8ux\n", e->ctlrno, cause);
1635 }
1636
1637 static void
1638 iproc(void *v)
1639 {
1640         uint cause, d;
1641         Ether *e;
1642         Ctlr *c;
1643
1644         e = v;
1645         c = e->ctlr;
1646         while(waserror())
1647                 ;
1648         for(;;){
1649                 starve(&c->iproc);
1650                 cause = c->reg[Eisr];
1651                 if(cause & Iphy)
1652                         link(e);
1653                 if(cause & Ihwerr)
1654                         hwerror(e, cause);
1655                 if(cause & Ierror)
1656                         eerror(e, cause & Ierror);
1657                 if(cause & Ibmu)
1658                         sring(e);
1659                 d = c->reg[Lisr];
1660                 USED(d);
1661         }
1662 }
1663
1664 static void
1665 interrupt(Ureg*, void *v)
1666 {
1667         uint cause;
1668         Ctlr *c;
1669         Ether *e;
1670
1671         e = v;
1672         c = e->ctlr;
1673
1674         /* reading Isrc2 masks interrupts */
1675         cause = c->reg[Isrc2];
1676         if(cause == 0 || cause == ~0){
1677                 /* reenable interrupts */
1678                 c->reg[Icr] = 2;
1679                 return;
1680         }
1681         unstarve(&c->iproc);
1682 }
1683
1684 static void
1685 storefw(Ctlr *c)
1686 {
1687         if(c->type == Yukex && c->rev != 1
1688         || c->type == Yukfep
1689         || c->type == Yuksup)
1690                 macwrite32(c, Gmfctl, Gmfjon | Gmfsfon);
1691         else{
1692                 macwrite32(c, Gmfae, 0x8000 | 0x70);    /* tx gmac fifo */
1693                 macwrite32(c, Gmfctl, Gmfsfoff);
1694         }
1695 }
1696
1697 static void
1698 raminit(Ctlr *c)
1699 {
1700         uint ram, rx;
1701
1702         if(ram = c->reg8[Ramcnt] * 4096/8){     /* in qwords */
1703                 c->flag |= Fram;
1704                 rx = ROUNDUP((2*ram)/3, 1024/8);
1705                 bufinit(c, Qr, 0, rx);
1706                 bufinit(c, Qtx, rx, ram);
1707                 rrwrite8(c, Qtxs + Rctl, Rrst); /* sync tx off */
1708         }else{
1709                 macwrite8(c, Rxplo, 768/8);
1710                 macwrite8(c, Rxphi, 1024/8);
1711                 storefw(c);
1712         }
1713 }
1714
1715 static void
1716 attach(Ether *e)
1717 {
1718         char buf[KNAMELEN];
1719         Ctlr *c;
1720         static Lock l;
1721
1722         c = e->ctlr;
1723         if(c->attach == 1)
1724                 return;
1725         lock(&l);
1726         if(c->attach == 1){
1727                 unlock(&l);
1728                 return;
1729         }
1730         c->attach = 1;
1731         unlock(&l);
1732
1733         snprint(buf, sizeof buf, "#l%dtproc", e->ctlrno);
1734         kproc(buf, tproc, e);
1735         snprint(buf, sizeof buf, "#l%drproc", e->ctlrno);
1736         kproc(buf, rproc, e);
1737         snprint(buf, sizeof buf, "#l%diproc", e->ctlrno);
1738         kproc(buf, iproc, e);
1739
1740         c->reg[Ism] |= Ibmu | Iport<<Iphy2base*c->portno;
1741 }
1742
1743 static long
1744 ifstat(Ether *e0, void *a, long n, ulong offset)
1745 {
1746         char *s, *e, *p;
1747         int i;
1748         uint u;
1749         Ctlr *c;
1750
1751         c = e0->ctlr;
1752         p = s = malloc(READSTR);
1753         e = p + READSTR;
1754         for(i = 0; i < nelem(stattab); i++){
1755                 u = gmacread32(c, Stats + stattab[i].offset/4);
1756                 if(u > 0)
1757                         p = seprint(p, e, "%s\t%ud\n", stattab[i].name, u);
1758         }
1759         p = seprint(p, e, "stat %.4ux ctl %.3ux\n", gmacread(c, Stat), gmacread(c, Ctl));
1760         p = seprint(p, e, "pref %.8ux %.4ux\n", prread32(c, Qr + Pctl), prread16(c, Qr + Pgetidx));
1761         if(debug){
1762                 p = dumppci(c, p, e);
1763                 p = dumpgmac(c, p, e);
1764                 p = dumpmac(c, p, e);
1765                 p = dumpreg(c, p, e);
1766         }
1767         seprint(p, e, "%s rev %d phy %s\n", idtab[c->type].name,
1768                 c->rev, c->feat&Ffiber? "fiber": "copper");
1769         n = readstr(offset, a, n, s);
1770         free(s);
1771         return n;
1772 }
1773
1774 static Cmdtab ctltab[] = {
1775         1,      "debug",                1,
1776         2,      "descriptorfu", 1,
1777 };
1778
1779 static long
1780 ctl(Ether *e, void *buf, long n)
1781 {
1782         Cmdbuf *cb;
1783         Cmdtab *t;
1784
1785         cb = parsecmd(buf, n);
1786         if(waserror()){
1787                 free(cb);
1788                 nexterror();
1789         }
1790         t = lookupcmd(cb, ctltab, nelem(ctltab));
1791         switch(t->index){
1792         case 0:
1793                 debug ^= 1;
1794                 break;
1795         case 1:
1796                 descriptorfu(e, Qr);
1797                 break;
1798         }
1799         free(cb);
1800         poperror();
1801         return n;
1802 }
1803
1804 static uint
1805 yukpcicfgr32(Ctlr *c, uint r)
1806 {
1807         return c->reg[r + 0x1c00>>2];
1808 }
1809
1810 static void
1811 yukpcicfgw32(Ctlr *c, uint r, uint v)
1812 {
1813         c->reg[r + 0x1c00>>2] = v;
1814 }
1815
1816 static void
1817 phypower(Ctlr *c)
1818 {
1819         uint u, u0;
1820
1821         u = u0 = yukpcicfgr32(c, Pciphy);
1822         u &= ~phypwr[c->portno];
1823         if(c->type == Yukxl && c->rev > 1)
1824                 u |= coma[c->portno];
1825         if(u != u0 || 1){
1826                 c->reg8[Tstctl1] = Tstwen;
1827                 yukpcicfgw32(c, Pciphy, u);
1828                 c->reg8[Tstctl1] = Tstwdis;
1829         }
1830         if(c->type == Yukfe)
1831                 c->reg8[Phyctl] = Aneen;
1832         else if(c->flag & Fapwr)
1833                 macwrite32(c, Phy, Gphyrstclr);
1834 }
1835
1836 static void
1837 phyinit(Ctlr *c)
1838 {
1839         uint u;
1840
1841         if((c->feat & Fnewphy) == 0){
1842                 u = phyread(c, Phyextctl);
1843                 u &= ~0xf70;                    /* clear downshift counters */
1844                 u |= 0x7<<4;                    /* mac tx clock = 25mhz */
1845                 if(c->type == Yukec)
1846                         u |= 2*Dnmstr | Dnslv;
1847                 else
1848                         u |= Dnslv;
1849                 phywrite(c, Phyextctl, u);
1850         }
1851         u = phyread(c, Phyphy);
1852
1853         /* questionable value */
1854         if(c->feat & Ffiber)
1855                 u &= ~Ppmdix;
1856         else if(c->feat & Fgbe){
1857                 u &= ~Pped;
1858                 u |= Ppmdixa;
1859                 if(c->flag & Fnewphy){
1860                 //      u &= ~(7<<12);
1861                 //      u |= 2*(1<<12) | 1<<11; /* like 2*Dnmstr | Dnslv */
1862                         u |= 2*(1<<9) | 1<<11;
1863                 }
1864         }else{
1865                 u |= Ppmdixa >> 1;              /* why the shift? */
1866                 if(c->type == Yukfep && c->rev == 0){
1867                 }
1868         }
1869
1870         phywrite(c, Phyphy, u);
1871         /* copper/fiber specific stuff gmacwrite(c, Ctl, 0); */
1872         gmacwrite(c, Ctl, 0);
1873         if(c->feat & Fgbe)
1874                 if(c->feat & Ffiber)
1875                         phywrite(c, Gbectl, Gbexf | Gbexh);
1876                 else
1877                         phywrite(c, Gbectl, Gbef | Gbeh);
1878         phywrite(c, Phyana, Anall);
1879         phywrite(c, Phyctl, Phyrst | Anerst | Aneen);
1880         /* chip specific stuff? */
1881         if (c->type == Yukfep){
1882                 u = phyread(c, Phyphy) | Ppnpe;
1883                 u &= ~(Ppengy | Ppscrdis);
1884                 phywrite(c, Phyphy, u);
1885 //              phywrite(c, 0x16, 0x0b54);              /* write to fe_led_par */
1886
1887                 /* yukfep and rev 0: apply workaround for integrated resistor calibration */
1888                 phywrite(c, Phypadr, 17);
1889                 phywrite(c, 0x1e, 0x3f60);
1890         }
1891         phywrite(c, Phyintm, Anok | Anerr | Lsc);
1892         dprint("phyid %.4ux step %.4ux\n", phyread(c, 2), phyread(c, 3));
1893 }
1894
1895 static int
1896 identify(Ctlr *c)
1897 {
1898         char t;
1899
1900         pcicfgw32(c->p, Pciclk, 0);
1901         c->reg16[Ctst] = Swclr;
1902
1903         c->type = c->reg8[Chip] - 0xb3;
1904         c->rev = c->reg8[Maccfg]>>4 & 0xf;
1905         if(c->type >= Nyuk)
1906                 return -1;
1907         if(idtab[c->type].okrev != 0xff)
1908         if(c->rev != idtab[c->type].okrev)
1909                 return -1;
1910         c->feat |= idtab[c->type].feat;
1911
1912         t = c->reg8[Pmd];
1913         if(t == 'L' || t == 'S' || t == 'P')
1914                 c->feat |= Ffiber;
1915         c->portno = 0;
1916         /* check second port ... whatever */
1917         return 0;
1918 }
1919
1920 static uint
1921 µ2clk(Ctlr *c, int µs)
1922 {
1923         return idtab[c->type].mhz * µs;
1924 }
1925
1926 static void
1927 gmacsetea(Ctlr *c, uint r)
1928 {
1929         uchar *ra;
1930         int i;
1931
1932         ra = c->ra;
1933         for(i = 0; i < Eaddrlen; i += 2)
1934                 gmacwrite(c, r + i, ra[i + 0] | ra[i + 1]<<8);
1935 }
1936
1937 static int
1938 reset(Ctlr *c)
1939 {
1940         uint i, j;
1941         Block *b;
1942
1943         identify(c);
1944
1945         if(c->type == Yukex)
1946                 c->reg16[Asfcs/2] &= ~(Asfbrrst | Asfcpurst | Asfucrst);
1947         else
1948                 c->reg8[Asfcs] = Asfrst;
1949         c->reg16[Ctst] = Asfdis;
1950
1951         c->reg16[Ctst] = Swrst;
1952         c->reg16[Ctst] = Swclr;
1953
1954         c->reg8[Tstctl1] = Tstwen;
1955         pcicfgw16(c->p, PciPSR, pcicfgr16(c->p, PciPSR) | 0xf100);
1956         c->reg16[Ctst] = Mstrclr;
1957         /* fixup pcie extended error goes here */
1958
1959         c->reg8[Pwrctl] = Vauxen | Vccen | Vauxoff | Vccon;
1960         c->reg[Clkctl] = Clkdivdis;
1961         if(c->type == Yukxl && c->rev > 1)
1962                 c->reg8[Clkgate] = ~Link2inactive;
1963         else
1964                 c->reg8[Clkgate] = 0;
1965         if(c->flag & Fapwr){
1966                 pcicfgw32(c->p, Pciclk, 0);
1967                 pcicfgw32(c->p, Pciasp, pcicfgr32(c->p, Pciasp) & Aspmsk);
1968                 pcicfgw32(c->p, Pcistate, pcicfgr32(c->p, Pcistate) & Vmain);
1969                 pcicfgw32(c->p, Pcicf1, 0);
1970                 c->reg[Gpio] |= Norace;
1971                 print("yuk2: advanced power %.8ux\n", c->reg[Gpio]);
1972         }
1973         c->reg8[Tstctl1] = Tstwdis;
1974
1975         for(i = 0; i < c->nports; i++){
1976                 macwrite8(c, Linkctl, Linkrst);
1977                 macwrite8(c, Linkctl, Linkclr);
1978                 if(c->type == Yukex || c->type == Yuksup)
1979                         macwrite16(c, Mac, Nomacsec | Nortx);
1980         }
1981
1982         c->reg[Dpolltm] = Pollstop;
1983
1984         for(i = 0; i < c->nports; i++)
1985                 macwrite8(c, Txactl, Txaclr);
1986         for(i = 0; i < c->nports; i++){
1987                 c->reg8[i*64 + Rictl] = Riclr;
1988                 for(j = 0; j < 12; j++)
1989                         c->reg8[i*64 + Rib + j] = 36;   /* qword times */
1990         }
1991
1992         c->reg[Hwem] = Hdflt;
1993         macwrite8(c, Irqm, 0);
1994         for(i = 0; i < 4; i++)
1995                 gmacwrite(c, Mchash + 2*i, 0);
1996         gmacwrite(c, Rxctl, Ufilter | Mfilter | Rmcrc);
1997
1998         for(i = 0; i < nelem(c->tbring); i++)
1999                 if(b = c->tbring[i]){
2000                         c->tbring[i] = nil;
2001                         freeb(b);
2002                 }
2003         for(i = 0; i < nelem(c->rbring); i++)
2004                 if(b = c->rbring[i]){
2005                         c->rbring[i] = nil;
2006                         freeb(b);
2007                 }
2008
2009         memset(c->tbring, 0, sizeof c->tbring[0] * nelem(c->tbring));
2010         memset(c->rbring, 0, sizeof c->rbring[0] * nelem(c->rbring));
2011         memset(c->tx.r, 0, sizeof c->tx.r[0] * c->tx.cnt);
2012         memset(c->rx.r, 0, sizeof c->rx.r[0] * c->rx.cnt);
2013         memset(c->status.r, 0, sizeof c->status.r[0] * c->status.cnt);
2014         c->reg[Statctl] = Statrst;
2015         c->reg[Statctl] = Statclr;
2016         c->reg[Stataddr + 0] = Pciwaddrl(c->status.r);
2017         c->reg[Stataddr + 4] = Pciwaddrh(c->status.r);
2018         c->reg16[Stattl] = c->status.m;
2019         c->reg16[Statth] = 10;
2020         c->reg8[Statwm] = 16;
2021         if(c->type == Yukxl && c->rev == 0)
2022                 c->reg8[Statiwm] = 4;
2023         else
2024                 c->reg8[Statiwm] = 4; //16;
2025
2026         /* set transmit, isr,  level timers */
2027         c->reg[Tsti] = µ2clk(c, 1000);
2028         c->reg[Titi] = µ2clk(c, 20);
2029         c->reg[Tlti] = µ2clk(c, 100);
2030
2031         c->reg[Statctl] = Staton;
2032
2033         c->reg8[Tstc] = Tstart;
2034         c->reg8[Tltc] = Tstart;
2035         c->reg8[Titc] = Tstart;
2036
2037         return 0;
2038 }
2039
2040 static void
2041 macinit(Ctlr *c)
2042 {
2043         uint r, i;
2044
2045         r = macread32(c, Phy) & ~(Gphyrst | Gphyrstclr);
2046         macwrite32(c, Phy, r | Gphyrst);
2047         macwrite32(c, Phy, r | Gphyrstclr);
2048         /* macwrite32(c, Mac, Macrst); ? */
2049         macwrite32(c, Mac, Macrstclr);
2050
2051         if(c->type == Yukxl && c->rev == 0 && c->portno == 1){
2052         }
2053
2054         macread8(c, Irq);
2055         macwrite8(c, Irqm, Txurun);
2056
2057         phypower(c);
2058         phyinit(c);
2059
2060         gmacwrite(c, Phyaddr, (r = gmacread(c, Phyaddr)) | Mibclear);
2061         for(i = 0; i < nelem(stattab); i++)
2062                 gmacread32(c, Stats + stattab[i].offset/4);
2063         gmacwrite(c, Phyaddr, r);
2064
2065         gmacwrite(c, Txctl, 4<<10);     /* collision distance */
2066         gmacwrite(c, Txflow, 0xffff);   /* flow control */
2067         gmacwrite(c, Txparm, 3<<14 | 0xb<<9 | 0x1c<<4 | 4);
2068         gmacwrite(c, Rxctl, Ufilter | Mfilter | Rmcrc);
2069         gmacwrite(c, Serctl, 0x04<<11 /* blind */ | Jumboen | 0x1e /* ipig */);
2070
2071         gmacsetea(c, Ea0);
2072         gmacsetea(c, Ea1);
2073
2074         gmacwrite(c, Txmask, 0);
2075         gmacwrite(c, Rxmask, 0);
2076         gmacwrite(c, Trmask, 0);
2077
2078         macwrite32(c, Gfrxctl, Gfrstclr);
2079         r = Gfon | Gffon;
2080         if(c->type == Yukex || c->type == Yukfep)
2081                 r |= Gfroon;
2082         macwrite32(c, Gfrxctl, r);
2083         if(c->type == Yukxl)
2084                 macwrite32(c, Grxfm, 0);
2085         else
2086                 macwrite32(c, Grxfm, Ferror);
2087         if(c->type == Yukfep && c->rev == 0)
2088                 macwrite32(c, Grxft, 0x178);
2089         else
2090                 macwrite32(c, Grxft, 0xb);
2091
2092         macwrite32(c, Gmfctl, Gmfclr);  /* clear reset */
2093         macwrite32(c, Gmfctl, Gmfon);   /* on */
2094
2095         raminit(c);
2096         if(c->type == Yukfep && c->rev == 0)
2097                 c->reg[Gmfea] = c->reg[Gmfea] & ~3;
2098
2099         c->rxinit = 0;
2100         c->txinit = 0;
2101 }
2102
2103 static void*
2104 slice(void **v, uint r, uint sz)
2105 {
2106         uintptr a;
2107
2108         a = (uintptr)*v;
2109         a = ROUNDUP(a, r);
2110         *v = (void*)(a + sz);
2111         return (void*)a;
2112 }
2113
2114 static void
2115 setupr(Sring *r, uint cnt)
2116 {
2117         r->rp = 0;
2118         r->wp = 0;
2119         r->cnt = cnt;
2120         r->m = cnt - 1;
2121 }
2122
2123 static int
2124 setup(Ctlr *c)
2125 {
2126         uint n;
2127         void *v, *mem;
2128         Pcidev *p;
2129
2130         p = c->p;
2131         c->io = p->mem[0].bar&~0xf;
2132         mem = vmap(c->io, p->mem[0].size);
2133         if(mem == nil){
2134                 print("yuk: cant map %#p\n", c->io);
2135                 return -1;
2136         }
2137         c->p = p;
2138         c->reg = (uint*)mem;
2139         c->reg8 = (uchar*)mem;
2140         c->reg16 = (ushort*)mem;
2141         if(memcmp(c->ra, nilea, sizeof c->ra) == 0)
2142                 memmove(c->ra, c->reg8 + Macadr + 8*c->portno, Eaddrlen);
2143
2144         setupr(&c->status, Sringcnt);
2145         setupr(&c->tx, Tringcnt);
2146         setupr(&c->rx, Rringcnt);
2147
2148         n = sizeof c->status.r[0] * (c->status.cnt + c->tx.cnt + c->rx.cnt);
2149         n += 16*4096*2;                         /* rounding slop */
2150         c->alloc = xspanalloc(n, 16*4096, 0);   /* unknown alignment constraints */
2151         memset(c->alloc, 0, n);
2152
2153         v = c->alloc;
2154         c->status.r = slice(&v, 16*4096, sizeof c->status.r[0] * c->status.cnt);
2155         c->tx.r = slice(&v, 16*4096, sizeof c->tx.r[0] * c->tx.cnt);
2156         c->rx.r = slice(&v, 16*4096, sizeof c->rx.r[0] * c->rx.cnt);
2157
2158         c->nports = 1;                          /* BOTCH */
2159         pcisetbme(p);
2160         if(reset(c)){
2161                 print("yuk: cant reset\n");
2162                 pciclrbme(p);
2163                 free(c->alloc);
2164                 vunmap(mem, p->mem[0].size);
2165                 return -1;
2166         }
2167         macinit(c);
2168         return 0;
2169 }
2170
2171 static void
2172 shutdown(Ether *e)
2173 {
2174         Ctlr *c;
2175         Pcidev *p;
2176
2177         c = e->ctlr;
2178
2179         reset(c);
2180         if(0){
2181                 p = c->p;
2182                 vunmap(c->reg, p->mem[0].size);
2183                 free(c->alloc);
2184         }
2185 }
2186
2187 static void
2188 scan(void)
2189 {
2190         int i;
2191         Pcidev *p;
2192         Ctlr *c;
2193
2194         for(p = nil; p = pcimatch(p, 0, 0); ){
2195                 for(i = 0; i < nelem(vtab); i++)
2196                         if(vtab[i].vid == p->vid)
2197                         if(vtab[i].did == p->did)
2198                                 break;
2199                 if(i == nelem(vtab))
2200                         continue;
2201                 if(nctlr == nelem(ctlrtab)){
2202                         print("yuk: too many controllers\n");
2203                         return;
2204                 }
2205                 c = malloc(sizeof *c);
2206                 if(c == nil){
2207                         print("yuk: no memory for Ctlr\n");
2208                         return;
2209                 }
2210                 c->p = p;
2211                 c->qno = nctlr;
2212                 c->rbsz = vtab[i].mtu;
2213                 ctlrtab[nctlr++] = c;
2214         }
2215 }
2216
2217 static int
2218 pnp(Ether *e)
2219 {
2220         int i;
2221         Ctlr *c;
2222
2223         if(nctlr == 0)
2224                 scan();
2225         for(i = 0;; i++){
2226                 if(i == nctlr)
2227                         return -1;
2228                 c = ctlrtab[i];
2229                 if(c == nil || c->flag&Fprobe)
2230                         continue;
2231                 if(e->port != 0 && e->port != (ulong)c->reg)
2232                         continue;
2233                 c->flag |= Fprobe;
2234                 if(setup(c) != 0)
2235                         continue;
2236                 break;
2237         }
2238         e->ctlr = c;
2239         e->port = c->io;
2240         e->irq = c->p->intl;
2241         e->tbdf = c->p->tbdf;
2242         e->mbps = 1000;
2243         e->maxmtu = c->rbsz;
2244         memmove(e->ea, c->ra, Eaddrlen);
2245         e->arg = e;
2246         e->attach = attach;
2247         e->ctl = ctl;
2248         e->ifstat = ifstat;
2249         e->interrupt = interrupt;
2250         e->multicast = multicast;
2251         e->promiscuous = promiscuous;
2252         e->shutdown = shutdown;
2253         e->transmit = nil;
2254
2255         return 0;
2256 }
2257
2258 void
2259 etheryuklink(void)
2260 {
2261         addethercard("yuk", pnp);
2262 }