xref: /plan9-contrib/sys/src/9/bcm/ethergenet.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
1*5c47fe09SDavid du Colombier /*
2*5c47fe09SDavid du Colombier  * Broadcom 2711 native gigabit ethernet
3*5c47fe09SDavid du Colombier  *
4*5c47fe09SDavid du Colombier  *	from 9front
5*5c47fe09SDavid du Colombier  */
6*5c47fe09SDavid du Colombier 
7*5c47fe09SDavid du Colombier #include "u.h"
8*5c47fe09SDavid du Colombier #include "../port/lib.h"
9*5c47fe09SDavid du Colombier #include "mem.h"
10*5c47fe09SDavid du Colombier #include "dat.h"
11*5c47fe09SDavid du Colombier #include "fns.h"
12*5c47fe09SDavid du Colombier #include "io.h"
13*5c47fe09SDavid du Colombier #include "../port/netif.h"
14*5c47fe09SDavid du Colombier #include "etherif.h"
15*5c47fe09SDavid du Colombier #include "ethermii.h"
16*5c47fe09SDavid du Colombier 
17*5c47fe09SDavid du Colombier #define	MIIDBG	if(0)print
18*5c47fe09SDavid du Colombier 
19*5c47fe09SDavid du Colombier enum
20*5c47fe09SDavid du Colombier {
21*5c47fe09SDavid du Colombier 	Rbsz		= 10240,
22*5c47fe09SDavid du Colombier 	Maxtu		= 9014,
23*5c47fe09SDavid du Colombier 
24*5c47fe09SDavid du Colombier 	DmaOWN		= 0x8000,
25*5c47fe09SDavid du Colombier 	DmaSOP		= 0x2000,
26*5c47fe09SDavid du Colombier 	DmaEOP		= 0x4000,
27*5c47fe09SDavid du Colombier 	DmaRxLg		= 0x10,
28*5c47fe09SDavid du Colombier 	DmaRxNo		= 0x08,
29*5c47fe09SDavid du Colombier 	DmaRxErr	= 0x04,
30*5c47fe09SDavid du Colombier 	DmaRxCrc	= 0x02,
31*5c47fe09SDavid du Colombier 	DmaRxOv		= 0x01,
32*5c47fe09SDavid du Colombier 	DmaRxErrors	= DmaRxLg|DmaRxNo|DmaRxErr|DmaRxCrc|DmaRxOv,
33*5c47fe09SDavid du Colombier 
34*5c47fe09SDavid du Colombier 	DmaTxQtag	= 0x1F80,
35*5c47fe09SDavid du Colombier 	DmaTxUnderrun	= 0x0200,
36*5c47fe09SDavid du Colombier 	DmaTxAppendCrc	= 0x0040,
37*5c47fe09SDavid du Colombier 	DmaTxOwCrc	= 0x0020,
38*5c47fe09SDavid du Colombier 	DmaTxDoCsum	= 0x0010,
39*5c47fe09SDavid du Colombier 
40*5c47fe09SDavid du Colombier 	/* Ctlr->regs */
41*5c47fe09SDavid du Colombier 	SysRevision	= 0x00/4,
42*5c47fe09SDavid du Colombier 	SysPortCtrl	= 0x04/4,
43*5c47fe09SDavid du Colombier 		PortModeIntEphy	= 0,
44*5c47fe09SDavid du Colombier 		PortModeIntGphy = 1,
45*5c47fe09SDavid du Colombier 		PortModeExtEphy = 2,
46*5c47fe09SDavid du Colombier 		PortModeExtGphy = 3,
47*5c47fe09SDavid du Colombier 		PortModeExtRvmii50 = 4,
48*5c47fe09SDavid du Colombier 		PortModeExtRvmii25 = 16 | 4,
49*5c47fe09SDavid du Colombier 		LedActSourceMac = 1 << 9,
50*5c47fe09SDavid du Colombier 
51*5c47fe09SDavid du Colombier 	SysRbufFlushCtrl	= 0x08/4,
52*5c47fe09SDavid du Colombier 	SysTbufFlushCtrl	= 0x0C/4,
53*5c47fe09SDavid du Colombier 
54*5c47fe09SDavid du Colombier 	ExtRgmiiOobCtrl	= 0x8C/4,
55*5c47fe09SDavid du Colombier 		RgmiiLink	= 1 << 4,
56*5c47fe09SDavid du Colombier 		OobDisable	= 1 << 5,
57*5c47fe09SDavid du Colombier 		RgmiiModeEn	= 1 << 6,
58*5c47fe09SDavid du Colombier 		IdModeDis	= 1 << 16,
59*5c47fe09SDavid du Colombier 
60*5c47fe09SDavid du Colombier 	Intrl0		= 0x200/4,
61*5c47fe09SDavid du Colombier 		IrqScb		= 1 << 0,
62*5c47fe09SDavid du Colombier 		IrqEphy		= 1 << 1,
63*5c47fe09SDavid du Colombier 		IrqPhyDetR	= 1 << 2,
64*5c47fe09SDavid du Colombier 		IrqPhyDetF	= 1 << 3,
65*5c47fe09SDavid du Colombier 		IrqLinkUp	= 1 << 4,
66*5c47fe09SDavid du Colombier 		IrqLinkDown	= 1 << 5,
67*5c47fe09SDavid du Colombier 		IrqUmac		= 1 << 6,
68*5c47fe09SDavid du Colombier 		IrqUmacTsv	= 1 << 7,
69*5c47fe09SDavid du Colombier 		IrqTbufUnderrun	= 1 << 8,
70*5c47fe09SDavid du Colombier 		IrqRbufOverflow	= 1 << 9,
71*5c47fe09SDavid du Colombier 		IrqHfbSm	= 1 << 10,
72*5c47fe09SDavid du Colombier 		IrqHfbMm	= 1 << 11,
73*5c47fe09SDavid du Colombier 		IrqMpdR		= 1 << 12,
74*5c47fe09SDavid du Colombier 		IrqRxDmaDone	= 1 << 13,
75*5c47fe09SDavid du Colombier 		IrqRxDmaPDone	= 1 << 14,
76*5c47fe09SDavid du Colombier 		IrqRxDmaBDone	= 1 << 15,
77*5c47fe09SDavid du Colombier 		IrqTxDmaDone	= 1 << 16,
78*5c47fe09SDavid du Colombier 		IrqTxDmaPDone	= 1 << 17,
79*5c47fe09SDavid du Colombier 		IrqTxDmaBDone	= 1 << 18,
80*5c47fe09SDavid du Colombier 		IrqMdioDone	= 1 << 23,
81*5c47fe09SDavid du Colombier 		IrqMdioError	= 1 << 24,
82*5c47fe09SDavid du Colombier 	Intrl1		= 0x240/4,
83*5c47fe09SDavid du Colombier 		/* Intrl0/1 + ... */
84*5c47fe09SDavid du Colombier 		IntrSts		= 0x00/4,
85*5c47fe09SDavid du Colombier 		IntrSet		= 0x04/4,
86*5c47fe09SDavid du Colombier 		IntrClr		= 0x08/4,
87*5c47fe09SDavid du Colombier 		IntrMaskSts	= 0x0C/4,
88*5c47fe09SDavid du Colombier 		IntrMaskSet	= 0x10/4,
89*5c47fe09SDavid du Colombier 		IntrMaskClr	= 0x14/4,
90*5c47fe09SDavid du Colombier 
91*5c47fe09SDavid du Colombier 	RbufCtrl	= 0x300/4,
92*5c47fe09SDavid du Colombier 		Rbuf64En	= 1 << 0,
93*5c47fe09SDavid du Colombier 		RbufAlign2B	= 1 << 1,
94*5c47fe09SDavid du Colombier 		RbufBadDis	= 1 << 2,
95*5c47fe09SDavid du Colombier 
96*5c47fe09SDavid du Colombier 	RbufChkCtrl	= 0x314/4,
97*5c47fe09SDavid du Colombier 		RbufChkRxChkEn	= 1 << 0,
98*5c47fe09SDavid du Colombier 		RbufChkSkipFcs	= 1 << 4,
99*5c47fe09SDavid du Colombier 
100*5c47fe09SDavid du Colombier 	RbufOvflCnt	= 0x394/4,
101*5c47fe09SDavid du Colombier 	RbufErrCnt	= 0x398/4,
102*5c47fe09SDavid du Colombier 
103*5c47fe09SDavid du Colombier 	RbufEnergyCtrl	= 0x39c/4,
104*5c47fe09SDavid du Colombier 		RbufEeeEn	= 1 << 0,
105*5c47fe09SDavid du Colombier 		RbufPmEn	= 1 << 1,
106*5c47fe09SDavid du Colombier 
107*5c47fe09SDavid du Colombier 	RbufTbufSizeCtrl= 0x3b4/4,
108*5c47fe09SDavid du Colombier 
109*5c47fe09SDavid du Colombier 	TbufCtrl	= 0x600/4,
110*5c47fe09SDavid du Colombier 	TbufBpMc	= 0x60C/4,
111*5c47fe09SDavid du Colombier 	TbufEnergyCtrl	= 0x614/4,
112*5c47fe09SDavid du Colombier 
113*5c47fe09SDavid du Colombier 	UmacCmd		= 0x808/4,
114*5c47fe09SDavid du Colombier 		CmdTxEn		= 1 << 0,
115*5c47fe09SDavid du Colombier 		CmdRxEn		= 1 << 1,
116*5c47fe09SDavid du Colombier 		CmdSpeed10	= 0 << 2,
117*5c47fe09SDavid du Colombier 		CmdSpeed100	= 1 << 2,
118*5c47fe09SDavid du Colombier 		CmdSpeed1000	= 2 << 2,
119*5c47fe09SDavid du Colombier 		CmdSpeedMask	= 3 << 2,
120*5c47fe09SDavid du Colombier 		CmdProm		= 1 << 4,
121*5c47fe09SDavid du Colombier 		CmdPadEn	= 1 << 5,
122*5c47fe09SDavid du Colombier 		CmdCrcFwd	= 1 << 6,
123*5c47fe09SDavid du Colombier 		CmdPauseFwd	= 1 << 7,
124*5c47fe09SDavid du Colombier 		CmdRxPauseIgn	= 1 << 8,
125*5c47fe09SDavid du Colombier 		CmdTxAddrIn	= 1 << 9,
126*5c47fe09SDavid du Colombier 		CmdHdEn		= 1 << 10,
127*5c47fe09SDavid du Colombier 		CmdSwReset	= 1 << 13,
128*5c47fe09SDavid du Colombier 		CmdLclLoopEn	= 1 << 15,
129*5c47fe09SDavid du Colombier 		CmdAutoConfig	= 1 << 22,
130*5c47fe09SDavid du Colombier 		CmdCntlFrmEn	= 1 << 23,
131*5c47fe09SDavid du Colombier 		CmdNoLenChk	= 1 << 24,
132*5c47fe09SDavid du Colombier 		CmdRmtLoopEn	= 1 << 25,
133*5c47fe09SDavid du Colombier 		CmdPrblEn	= 1 << 27,
134*5c47fe09SDavid du Colombier 		CmdTxPauseIgn	= 1 << 28,
135*5c47fe09SDavid du Colombier 		CmdTxRxEn	= 1 << 29,
136*5c47fe09SDavid du Colombier 		CmdRuntFilterDis= 1 << 30,
137*5c47fe09SDavid du Colombier 
138*5c47fe09SDavid du Colombier 	UmacMac0	= 0x80C/4,
139*5c47fe09SDavid du Colombier 	UmacMac1	= 0x810/4,
140*5c47fe09SDavid du Colombier 	UmacMaxFrameLen	= 0x814/4,
141*5c47fe09SDavid du Colombier 
142*5c47fe09SDavid du Colombier 	UmacEeeCtrl	= 0x864/4,
143*5c47fe09SDavid du Colombier 		UmacEeeEn	= 1<<3,
144*5c47fe09SDavid du Colombier 
145*5c47fe09SDavid du Colombier 	UmacEeeLpiTimer	= 0x868/4,
146*5c47fe09SDavid du Colombier 	UmacEeeWakeTimer= 0x86C/4,
147*5c47fe09SDavid du Colombier 	UmacEeeRefCount	= 0x870/4,
148*5c47fe09SDavid du Colombier 		EeeRefCountMask = 0xFFFF,
149*5c47fe09SDavid du Colombier 
150*5c47fe09SDavid du Colombier 	UmacTxFlush	= 0xb34/4,
151*5c47fe09SDavid du Colombier 
152*5c47fe09SDavid du Colombier 	UmacMibCtrl	= 0xd80/4,
153*5c47fe09SDavid du Colombier 		MibResetRx	= 1 << 0,
154*5c47fe09SDavid du Colombier 		MibResetRunt	= 1 << 1,
155*5c47fe09SDavid du Colombier 		MibResetTx	= 1 << 2,
156*5c47fe09SDavid du Colombier 
157*5c47fe09SDavid du Colombier 	MdioCmd		= 0xe14/4,
158*5c47fe09SDavid du Colombier 		MdioStartBusy	= 1 << 29,
159*5c47fe09SDavid du Colombier 		MdioReadFail	= 1 << 28,
160*5c47fe09SDavid du Colombier 		MdioRead	= 2 << 26,
161*5c47fe09SDavid du Colombier 		MdioWrite	= 1 << 26,
162*5c47fe09SDavid du Colombier 		MdioPhyShift	= 21,
163*5c47fe09SDavid du Colombier 		MdioPhyMask	= 0x1F,
164*5c47fe09SDavid du Colombier 		MdioAddrShift	= 16,
165*5c47fe09SDavid du Colombier 		MdioAddrMask	= 0x1F,
166*5c47fe09SDavid du Colombier 
167*5c47fe09SDavid du Colombier 	UmacMpdCtrl	= 0xe20/4,
168*5c47fe09SDavid du Colombier 		MpdEn	= 1 << 0,
169*5c47fe09SDavid du Colombier 		MpdPwEn	= 1 << 27,
170*5c47fe09SDavid du Colombier 
171*5c47fe09SDavid du Colombier 	UmacMdfCtrl	= 0xe50/4,
172*5c47fe09SDavid du Colombier 	UmacMdfAddr0	= 0xe54/4,
173*5c47fe09SDavid du Colombier 
174*5c47fe09SDavid du Colombier 	RdmaOffset	= 0x2000/4,
175*5c47fe09SDavid du Colombier 	TdmaOffset	= 0x4000/4,
176*5c47fe09SDavid du Colombier 	HfbOffset	= 0x8000/4,
177*5c47fe09SDavid du Colombier 
178*5c47fe09SDavid du Colombier 	HfbCtlr		= 0xFC00/4,
179*5c47fe09SDavid du Colombier 	HfbFltEnable	= 0xFC04/4,
180*5c47fe09SDavid du Colombier 	HfbFltLen	= 0xFC1C/4,
181*5c47fe09SDavid du Colombier 
182*5c47fe09SDavid du Colombier 	/* common Ring->regs */
183*5c47fe09SDavid du Colombier 	RdmaWP		= 0x00/4,
184*5c47fe09SDavid du Colombier 	TdmaRP		= 0x00/4,
185*5c47fe09SDavid du Colombier 	RxWP		= 0x08/4,
186*5c47fe09SDavid du Colombier 	TxRP		= 0x08/4,
187*5c47fe09SDavid du Colombier 	TxWP		= 0x0C/4,
188*5c47fe09SDavid du Colombier 	RxRP		= 0x0C/4,
189*5c47fe09SDavid du Colombier 	DmaRingBufSize	= 0x10/4,
190*5c47fe09SDavid du Colombier 	DmaStart	= 0x14/4,
191*5c47fe09SDavid du Colombier 	DmaEnd		= 0x1C/4,
192*5c47fe09SDavid du Colombier 	DmaDoneThresh	= 0x24/4,
193*5c47fe09SDavid du Colombier 	TdmaFlowPeriod	= 0x28/4,
194*5c47fe09SDavid du Colombier 	RdmaXonXoffThresh=0x28/4,
195*5c47fe09SDavid du Colombier 	TdmaWP		= 0x2C/4,
196*5c47fe09SDavid du Colombier 	RdmaRP		= 0x2C/4,
197*5c47fe09SDavid du Colombier 
198*5c47fe09SDavid du Colombier 	/*
199*5c47fe09SDavid du Colombier 	 * reg offsets only for RING16
200*5c47fe09SDavid du Colombier 	 * ctlr->rx->regs / ctlr->tx->regs
201*5c47fe09SDavid du Colombier 	 */
202*5c47fe09SDavid du Colombier 	RingCfg		= 0x40/4,
203*5c47fe09SDavid du Colombier 		RxRingCfgMask	= 0x10000,
204*5c47fe09SDavid du Colombier 		TxRingCfgMask	= 0x1000F,
205*5c47fe09SDavid du Colombier 
206*5c47fe09SDavid du Colombier 	DmaCtrl		= 0x44/4,
207*5c47fe09SDavid du Colombier 		DmaCtrlEn	= 1 << 0,
208*5c47fe09SDavid du Colombier 	DmaStatus	= 0x48/4,
209*5c47fe09SDavid du Colombier 		DmaStatusDis	= 1 << 0,
210*5c47fe09SDavid du Colombier 	DmaScbBurstSize	= 0x4C/4,
211*5c47fe09SDavid du Colombier 
212*5c47fe09SDavid du Colombier 	TdmaArbCtrl	= 0x6C/4,
213*5c47fe09SDavid du Colombier 	TdmaPriority0	= 0x70/4,
214*5c47fe09SDavid du Colombier 	TdmaPriority1	= 0x74/4,
215*5c47fe09SDavid du Colombier 	TdmaPriority2	= 0x78/4,
216*5c47fe09SDavid du Colombier 
217*5c47fe09SDavid du Colombier 	RdmaTimeout0	= 0x6C/4,
218*5c47fe09SDavid du Colombier 	RdmaIndex2Ring0	= 0xB0/4,
219*5c47fe09SDavid du Colombier };
220*5c47fe09SDavid du Colombier 
221*5c47fe09SDavid du Colombier typedef struct Desc Desc;
222*5c47fe09SDavid du Colombier typedef struct Ring Ring;
223*5c47fe09SDavid du Colombier typedef struct Ctlr Ctlr;
224*5c47fe09SDavid du Colombier 
225*5c47fe09SDavid du Colombier struct Desc
226*5c47fe09SDavid du Colombier {
227*5c47fe09SDavid du Colombier 	u32int	*d;	/* hw descriptor */
228*5c47fe09SDavid du Colombier 	Block	*b;
229*5c47fe09SDavid du Colombier };
230*5c47fe09SDavid du Colombier 
231*5c47fe09SDavid du Colombier struct Ring
232*5c47fe09SDavid du Colombier {
233*5c47fe09SDavid du Colombier 	Rendez;
234*5c47fe09SDavid du Colombier 	u32int	*regs;
235*5c47fe09SDavid du Colombier 	u32int	*intregs;
236*5c47fe09SDavid du Colombier 	u32int	intmask;
237*5c47fe09SDavid du Colombier 
238*5c47fe09SDavid du Colombier 	Desc	*d;
239*5c47fe09SDavid du Colombier 
240*5c47fe09SDavid du Colombier 	u32int	m;
241*5c47fe09SDavid du Colombier 	u32int	cp;
242*5c47fe09SDavid du Colombier 	u32int	rp;
243*5c47fe09SDavid du Colombier 	u32int	wp;
244*5c47fe09SDavid du Colombier 
245*5c47fe09SDavid du Colombier 	int	num;
246*5c47fe09SDavid du Colombier };
247*5c47fe09SDavid du Colombier 
248*5c47fe09SDavid du Colombier struct Ctlr
249*5c47fe09SDavid du Colombier {
250*5c47fe09SDavid du Colombier 	Lock;
251*5c47fe09SDavid du Colombier 	u32int	*regs;
252*5c47fe09SDavid du Colombier 
253*5c47fe09SDavid du Colombier 	Desc	rd[256];
254*5c47fe09SDavid du Colombier 	Desc	td[256];
255*5c47fe09SDavid du Colombier 
256*5c47fe09SDavid du Colombier 	Ring	rx[1+0];
257*5c47fe09SDavid du Colombier 	Ring	tx[1+0];
258*5c47fe09SDavid du Colombier 
259*5c47fe09SDavid du Colombier 	Rendez	avail[1];
260*5c47fe09SDavid du Colombier 	Rendez	link[1];
261*5c47fe09SDavid du Colombier 	struct {
262*5c47fe09SDavid du Colombier 		Mii;
263*5c47fe09SDavid du Colombier 		Rendez;
264*5c47fe09SDavid du Colombier 	}	mii[1];
265*5c47fe09SDavid du Colombier 
266*5c47fe09SDavid du Colombier 	QLock;
267*5c47fe09SDavid du Colombier 	char	attached;
268*5c47fe09SDavid du Colombier };
269*5c47fe09SDavid du Colombier 
270*5c47fe09SDavid du Colombier static Block *scratch;
271*5c47fe09SDavid du Colombier 
272*5c47fe09SDavid du Colombier #define	REG(x)	(x)
273*5c47fe09SDavid du Colombier 
274*5c47fe09SDavid du Colombier static void
interrupt0(Ureg *,void * arg)275*5c47fe09SDavid du Colombier interrupt0(Ureg*, void *arg)
276*5c47fe09SDavid du Colombier {
277*5c47fe09SDavid du Colombier 	Ether *edev = arg;
278*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
279*5c47fe09SDavid du Colombier 	u32int sts;
280*5c47fe09SDavid du Colombier 
281*5c47fe09SDavid du Colombier 	sts = REG(ctlr->regs[Intrl0 + IntrSts]) & ~REG(ctlr->regs[Intrl0 + IntrMaskSts]);
282*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl0 + IntrClr]) = sts;
283*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl0 + IntrMaskSet]) = sts;
284*5c47fe09SDavid du Colombier 
285*5c47fe09SDavid du Colombier 	if(sts & ctlr->rx->intmask)
286*5c47fe09SDavid du Colombier 		wakeup(ctlr->rx);
287*5c47fe09SDavid du Colombier 	if(sts & ctlr->tx->intmask)
288*5c47fe09SDavid du Colombier 		wakeup(ctlr->tx);
289*5c47fe09SDavid du Colombier 
290*5c47fe09SDavid du Colombier 	if(sts & (IrqMdioDone|IrqMdioError))
291*5c47fe09SDavid du Colombier 		wakeup(ctlr->mii);
292*5c47fe09SDavid du Colombier 	if(sts & (IrqLinkUp|IrqLinkDown))
293*5c47fe09SDavid du Colombier 		wakeup(ctlr->link);
294*5c47fe09SDavid du Colombier }
295*5c47fe09SDavid du Colombier 
296*5c47fe09SDavid du Colombier static void
interrupt1(Ureg *,void * arg)297*5c47fe09SDavid du Colombier interrupt1(Ureg*, void *arg)
298*5c47fe09SDavid du Colombier {
299*5c47fe09SDavid du Colombier 	Ether *edev = arg;
300*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
301*5c47fe09SDavid du Colombier 	u32int sts;
302*5c47fe09SDavid du Colombier 	int i;
303*5c47fe09SDavid du Colombier 
304*5c47fe09SDavid du Colombier 	sts = REG(ctlr->regs[Intrl1 + IntrSts]) & ~REG(ctlr->regs[Intrl1 + IntrMaskSts]);
305*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl1 + IntrClr]) = sts;
306*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl1 + IntrMaskSet]) = sts;
307*5c47fe09SDavid du Colombier 
308*5c47fe09SDavid du Colombier 	for(i = 1; i < nelem(ctlr->rx); i++)
309*5c47fe09SDavid du Colombier 		if(sts & ctlr->rx[i].intmask)
310*5c47fe09SDavid du Colombier 			wakeup(&ctlr->rx[i]);
311*5c47fe09SDavid du Colombier 
312*5c47fe09SDavid du Colombier 	for(i = 1; i < nelem(ctlr->tx); i++)
313*5c47fe09SDavid du Colombier 		if(sts & ctlr->tx[i].intmask)
314*5c47fe09SDavid du Colombier 			wakeup(&ctlr->tx[i]);
315*5c47fe09SDavid du Colombier }
316*5c47fe09SDavid du Colombier 
317*5c47fe09SDavid du Colombier static void
setdma(Desc * d,void * v)318*5c47fe09SDavid du Colombier setdma(Desc *d, void *v)
319*5c47fe09SDavid du Colombier {
320*5c47fe09SDavid du Colombier 	u64int pa = PADDR(v);
321*5c47fe09SDavid du Colombier 	REG(d->d[1]) = pa;
322*5c47fe09SDavid du Colombier 	REG(d->d[2]) = pa >> 32;
323*5c47fe09SDavid du Colombier }
324*5c47fe09SDavid du Colombier 
325*5c47fe09SDavid du Colombier static void
replenish(Desc * d)326*5c47fe09SDavid du Colombier replenish(Desc *d)
327*5c47fe09SDavid du Colombier {
328*5c47fe09SDavid du Colombier 	d->b = allocb(Rbsz);
329*5c47fe09SDavid du Colombier 	cachedwbse(d->b->rp, Rbsz);
330*5c47fe09SDavid du Colombier 	setdma(d, d->b->rp);
331*5c47fe09SDavid du Colombier }
332*5c47fe09SDavid du Colombier 
333*5c47fe09SDavid du Colombier static int
rxdone(void * arg)334*5c47fe09SDavid du Colombier rxdone(void *arg)
335*5c47fe09SDavid du Colombier {
336*5c47fe09SDavid du Colombier 	Ring *r = arg;
337*5c47fe09SDavid du Colombier 
338*5c47fe09SDavid du Colombier 	r->wp = REG(r->regs[RxWP]) & 0xFFFF;
339*5c47fe09SDavid du Colombier 	if(r->rp != r->wp)
340*5c47fe09SDavid du Colombier 		return 1;
341*5c47fe09SDavid du Colombier 	REG(r->intregs[IntrMaskClr]) = r->intmask;
342*5c47fe09SDavid du Colombier 	return 0;
343*5c47fe09SDavid du Colombier }
344*5c47fe09SDavid du Colombier 
345*5c47fe09SDavid du Colombier static void
recvproc(void * arg)346*5c47fe09SDavid du Colombier recvproc(void *arg)
347*5c47fe09SDavid du Colombier {
348*5c47fe09SDavid du Colombier 	Ether *edev = arg;
349*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
350*5c47fe09SDavid du Colombier 	Desc *d;
351*5c47fe09SDavid du Colombier 	Block *b;
352*5c47fe09SDavid du Colombier 	u32int s;
353*5c47fe09SDavid du Colombier 
354*5c47fe09SDavid du Colombier 	while(waserror())
355*5c47fe09SDavid du Colombier 		;
356*5c47fe09SDavid du Colombier 
357*5c47fe09SDavid du Colombier 	for(;;){
358*5c47fe09SDavid du Colombier 		if(ctlr->rx->rp == ctlr->rx->wp){
359*5c47fe09SDavid du Colombier 			sleep(ctlr->rx, rxdone, ctlr->rx);
360*5c47fe09SDavid du Colombier 			continue;
361*5c47fe09SDavid du Colombier 		}
362*5c47fe09SDavid du Colombier 		d = &ctlr->rx->d[ctlr->rx->rp & ctlr->rx->m];
363*5c47fe09SDavid du Colombier 		b = d->b;
364*5c47fe09SDavid du Colombier 		cachedinvse(b->rp, Rbsz);
365*5c47fe09SDavid du Colombier 		s = REG(d->d[0]);
366*5c47fe09SDavid du Colombier 		replenish(d);
367*5c47fe09SDavid du Colombier 		coherence();
368*5c47fe09SDavid du Colombier 		ctlr->rx->rp = (ctlr->rx->rp + 1) & 0xFFFF;
369*5c47fe09SDavid du Colombier 		REG(ctlr->rx->regs[RxRP]) = ctlr->rx->rp;
370*5c47fe09SDavid du Colombier 		if((s & (DmaSOP|DmaEOP|DmaRxErrors)) != (DmaSOP|DmaEOP)){
371*5c47fe09SDavid du Colombier 			freeb(b);
372*5c47fe09SDavid du Colombier 			continue;
373*5c47fe09SDavid du Colombier 		}
374*5c47fe09SDavid du Colombier 		b->wp += (s & 0x7FFF0000) >> 16;
375*5c47fe09SDavid du Colombier 		etheriq(edev, b, 1);
376*5c47fe09SDavid du Colombier 	}
377*5c47fe09SDavid du Colombier }
378*5c47fe09SDavid du Colombier 
379*5c47fe09SDavid du Colombier static int
txavail(void * arg)380*5c47fe09SDavid du Colombier txavail(void *arg)
381*5c47fe09SDavid du Colombier {
382*5c47fe09SDavid du Colombier 	Ring *r = arg;
383*5c47fe09SDavid du Colombier 
384*5c47fe09SDavid du Colombier 	return ((r->wp+1) & r->m) != (r->cp & r->m);
385*5c47fe09SDavid du Colombier }
386*5c47fe09SDavid du Colombier 
387*5c47fe09SDavid du Colombier static void
sendproc(void * arg)388*5c47fe09SDavid du Colombier sendproc(void *arg)
389*5c47fe09SDavid du Colombier {
390*5c47fe09SDavid du Colombier 	Ether *edev = arg;
391*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
392*5c47fe09SDavid du Colombier 	Desc *d;
393*5c47fe09SDavid du Colombier 	Block *b;
394*5c47fe09SDavid du Colombier 
395*5c47fe09SDavid du Colombier 	while(waserror())
396*5c47fe09SDavid du Colombier 		;
397*5c47fe09SDavid du Colombier 
398*5c47fe09SDavid du Colombier 	for(;;){
399*5c47fe09SDavid du Colombier 		if(!txavail(ctlr->tx)){
400*5c47fe09SDavid du Colombier 			sleep(ctlr->avail, txavail, ctlr->tx);
401*5c47fe09SDavid du Colombier 			continue;
402*5c47fe09SDavid du Colombier 		}
403*5c47fe09SDavid du Colombier 		if((b = qbread(edev->oq, 100000)) == nil)
404*5c47fe09SDavid du Colombier 			break;
405*5c47fe09SDavid du Colombier 		d = &ctlr->tx->d[ctlr->tx->wp & ctlr->tx->m];
406*5c47fe09SDavid du Colombier 		assert(d->b == nil);
407*5c47fe09SDavid du Colombier 		d->b = b;
408*5c47fe09SDavid du Colombier 		cachedwbse(b->rp, BLEN(b));
409*5c47fe09SDavid du Colombier 		setdma(d, b->rp);
410*5c47fe09SDavid du Colombier 		REG(d->d[0]) = BLEN(b)<<16 | DmaTxQtag | DmaSOP | DmaEOP | DmaTxAppendCrc;
411*5c47fe09SDavid du Colombier 		coherence();
412*5c47fe09SDavid du Colombier 		ctlr->tx->wp = (ctlr->tx->wp+1) & 0xFFFF;
413*5c47fe09SDavid du Colombier 		REG(ctlr->tx->regs[TxWP]) = ctlr->tx->wp;
414*5c47fe09SDavid du Colombier 	}
415*5c47fe09SDavid du Colombier }
416*5c47fe09SDavid du Colombier 
417*5c47fe09SDavid du Colombier static int
txdone(void * arg)418*5c47fe09SDavid du Colombier txdone(void *arg)
419*5c47fe09SDavid du Colombier {
420*5c47fe09SDavid du Colombier 	Ring *r = arg;
421*5c47fe09SDavid du Colombier 
422*5c47fe09SDavid du Colombier 	if(r->cp != r->wp){
423*5c47fe09SDavid du Colombier 		r->rp = REG(r->regs[TxRP]) & 0xFFFF;
424*5c47fe09SDavid du Colombier 		if(r->cp != r->rp)
425*5c47fe09SDavid du Colombier 			return 1;
426*5c47fe09SDavid du Colombier 	}
427*5c47fe09SDavid du Colombier 	REG(r->intregs[IntrMaskClr]) = r->intmask;
428*5c47fe09SDavid du Colombier 	return 0;
429*5c47fe09SDavid du Colombier }
430*5c47fe09SDavid du Colombier 
431*5c47fe09SDavid du Colombier static void
freeproc(void * arg)432*5c47fe09SDavid du Colombier freeproc(void *arg)
433*5c47fe09SDavid du Colombier {
434*5c47fe09SDavid du Colombier 	Ether *edev = arg;
435*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
436*5c47fe09SDavid du Colombier 	Desc *d;
437*5c47fe09SDavid du Colombier 
438*5c47fe09SDavid du Colombier 	while(waserror())
439*5c47fe09SDavid du Colombier 		;
440*5c47fe09SDavid du Colombier 
441*5c47fe09SDavid du Colombier 	for(;;){
442*5c47fe09SDavid du Colombier 		if(ctlr->tx->cp == ctlr->tx->rp){
443*5c47fe09SDavid du Colombier 			wakeup(ctlr->avail);
444*5c47fe09SDavid du Colombier 			sleep(ctlr->tx, txdone, ctlr->tx);
445*5c47fe09SDavid du Colombier 			continue;
446*5c47fe09SDavid du Colombier 		}
447*5c47fe09SDavid du Colombier 		d = &ctlr->tx->d[ctlr->tx->cp & ctlr->tx->m];
448*5c47fe09SDavid du Colombier 		assert(d->b != nil);
449*5c47fe09SDavid du Colombier 		freeb(d->b);
450*5c47fe09SDavid du Colombier 		d->b = nil;
451*5c47fe09SDavid du Colombier 		coherence();
452*5c47fe09SDavid du Colombier 		ctlr->tx->cp = (ctlr->tx->cp+1) & 0xFFFF;
453*5c47fe09SDavid du Colombier 	}
454*5c47fe09SDavid du Colombier }
455*5c47fe09SDavid du Colombier 
456*5c47fe09SDavid du Colombier static void
initring(Ring * ring,Desc * desc,int start,int size)457*5c47fe09SDavid du Colombier initring(Ring *ring, Desc *desc, int start, int size)
458*5c47fe09SDavid du Colombier {
459*5c47fe09SDavid du Colombier 	ring->d = &desc[start];
460*5c47fe09SDavid du Colombier 	ring->m = size - 1;
461*5c47fe09SDavid du Colombier 	ring->cp = ring->rp = ring->wp = 0;
462*5c47fe09SDavid du Colombier 	REG(ring->regs[RxWP]) = 0;
463*5c47fe09SDavid du Colombier 	REG(ring->regs[RxRP]) = 0;
464*5c47fe09SDavid du Colombier 	REG(ring->regs[DmaStart]) = start*3;
465*5c47fe09SDavid du Colombier 	REG(ring->regs[DmaEnd]) = (start+size)*3 - 1;
466*5c47fe09SDavid du Colombier 	REG(ring->regs[RdmaWP]) = start*3;
467*5c47fe09SDavid du Colombier 	REG(ring->regs[RdmaRP]) = start*3;
468*5c47fe09SDavid du Colombier 	REG(ring->regs[DmaRingBufSize]) = (size << 16) | Rbsz;
469*5c47fe09SDavid du Colombier 	REG(ring->regs[DmaDoneThresh]) = 1;
470*5c47fe09SDavid du Colombier }
471*5c47fe09SDavid du Colombier 
472*5c47fe09SDavid du Colombier static void
introff(Ctlr * ctlr)473*5c47fe09SDavid du Colombier introff(Ctlr *ctlr)
474*5c47fe09SDavid du Colombier {
475*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl0 + IntrMaskSet]) = -1;
476*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl0 + IntrClr]) = -1;
477*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl1 + IntrMaskSet]) = -1;
478*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl1 + IntrClr]) = -1;
479*5c47fe09SDavid du Colombier }
480*5c47fe09SDavid du Colombier 
481*5c47fe09SDavid du Colombier static void
dmaoff(Ctlr * ctlr)482*5c47fe09SDavid du Colombier dmaoff(Ctlr *ctlr)
483*5c47fe09SDavid du Colombier {
484*5c47fe09SDavid du Colombier 	REG(ctlr->rx->regs[DmaCtrl]) &= ~(RxRingCfgMask<<1 | DmaCtrlEn);
485*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[DmaCtrl]) &= ~(TxRingCfgMask<<1 | DmaCtrlEn);
486*5c47fe09SDavid du Colombier 
487*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacTxFlush]) = 1;
488*5c47fe09SDavid du Colombier 	microdelay(10);
489*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacTxFlush]) = 0;
490*5c47fe09SDavid du Colombier 
491*5c47fe09SDavid du Colombier 	while((REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis) == 0)
492*5c47fe09SDavid du Colombier 		microdelay(10);
493*5c47fe09SDavid du Colombier 	while((REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis) == 0)
494*5c47fe09SDavid du Colombier 		microdelay(10);
495*5c47fe09SDavid du Colombier }
496*5c47fe09SDavid du Colombier 
497*5c47fe09SDavid du Colombier static void
dmaon(Ctlr * ctlr)498*5c47fe09SDavid du Colombier dmaon(Ctlr *ctlr)
499*5c47fe09SDavid du Colombier {
500*5c47fe09SDavid du Colombier 	REG(ctlr->rx->regs[DmaCtrl]) |= DmaCtrlEn;
501*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[DmaCtrl]) |= DmaCtrlEn;
502*5c47fe09SDavid du Colombier 
503*5c47fe09SDavid du Colombier 	while(REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis)
504*5c47fe09SDavid du Colombier 		microdelay(10);
505*5c47fe09SDavid du Colombier 	while(REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis)
506*5c47fe09SDavid du Colombier 		microdelay(10);
507*5c47fe09SDavid du Colombier }
508*5c47fe09SDavid du Colombier 
509*5c47fe09SDavid du Colombier static void
allocbufs(Ctlr * ctlr)510*5c47fe09SDavid du Colombier allocbufs(Ctlr *ctlr)
511*5c47fe09SDavid du Colombier {
512*5c47fe09SDavid du Colombier 	int i;
513*5c47fe09SDavid du Colombier 
514*5c47fe09SDavid du Colombier 	if(scratch == nil){
515*5c47fe09SDavid du Colombier 		scratch = allocb(Rbsz);
516*5c47fe09SDavid du Colombier 		memset(scratch->rp, 0xFF, Rbsz);
517*5c47fe09SDavid du Colombier 		cachedwbse(scratch->rp, Rbsz);
518*5c47fe09SDavid du Colombier 	}
519*5c47fe09SDavid du Colombier 
520*5c47fe09SDavid du Colombier 	for(i = 0; i < nelem(ctlr->rd); i++){
521*5c47fe09SDavid du Colombier 		ctlr->rd[i].d = &ctlr->regs[RdmaOffset + i*3];
522*5c47fe09SDavid du Colombier 		replenish(&ctlr->rd[i]);
523*5c47fe09SDavid du Colombier 	}
524*5c47fe09SDavid du Colombier 
525*5c47fe09SDavid du Colombier 	for(i = 0; i < nelem(ctlr->td); i++){
526*5c47fe09SDavid du Colombier 		ctlr->td[i].d = &ctlr->regs[TdmaOffset + i*3];
527*5c47fe09SDavid du Colombier 		setdma(&ctlr->td[i], scratch->rp);
528*5c47fe09SDavid du Colombier 		REG(ctlr->td[i].d[0]) = DmaTxUnderrun;
529*5c47fe09SDavid du Colombier 	}
530*5c47fe09SDavid du Colombier }
531*5c47fe09SDavid du Colombier 
532*5c47fe09SDavid du Colombier static void
freebufs(Ctlr * ctlr)533*5c47fe09SDavid du Colombier freebufs(Ctlr *ctlr)
534*5c47fe09SDavid du Colombier {
535*5c47fe09SDavid du Colombier 	int i;
536*5c47fe09SDavid du Colombier 
537*5c47fe09SDavid du Colombier 	for(i = 0; i < nelem(ctlr->rd); i++){
538*5c47fe09SDavid du Colombier 		if(ctlr->rd[i].b != nil){
539*5c47fe09SDavid du Colombier 			freeb(ctlr->rd[i].b);
540*5c47fe09SDavid du Colombier 			ctlr->rd[i].b = nil;
541*5c47fe09SDavid du Colombier 		}
542*5c47fe09SDavid du Colombier 	}
543*5c47fe09SDavid du Colombier 	for(i = 0; i < nelem(ctlr->td); i++){
544*5c47fe09SDavid du Colombier 		if(ctlr->td[i].b != nil){
545*5c47fe09SDavid du Colombier 			freeb(ctlr->td[i].b);
546*5c47fe09SDavid du Colombier 			ctlr->td[i].b = nil;
547*5c47fe09SDavid du Colombier 		}
548*5c47fe09SDavid du Colombier 	}
549*5c47fe09SDavid du Colombier }
550*5c47fe09SDavid du Colombier 
551*5c47fe09SDavid du Colombier static void
initrings(Ctlr * ctlr)552*5c47fe09SDavid du Colombier initrings(Ctlr *ctlr)
553*5c47fe09SDavid du Colombier {
554*5c47fe09SDavid du Colombier 	u32int rcfg, tcfg, dmapri[3];
555*5c47fe09SDavid du Colombier 	int i;
556*5c47fe09SDavid du Colombier 
557*5c47fe09SDavid du Colombier 	ctlr->rx->intregs = &ctlr->regs[Intrl0];
558*5c47fe09SDavid du Colombier 	ctlr->rx->intmask = IrqRxDmaDone;
559*5c47fe09SDavid du Colombier 	ctlr->rx->num = 16;
560*5c47fe09SDavid du Colombier 	rcfg = 1<<16;
561*5c47fe09SDavid du Colombier 	for(i = 1; i < nelem(ctlr->rx); i++){
562*5c47fe09SDavid du Colombier 		ctlr->rx[i].regs = &ctlr->regs[RdmaOffset + nelem(ctlr->rd)*3 + (i-1)*RingCfg];
563*5c47fe09SDavid du Colombier 		ctlr->rx[i].intregs = &ctlr->regs[Intrl1];
564*5c47fe09SDavid du Colombier 		ctlr->rx[i].intmask = 0x10000 << (i - 1);
565*5c47fe09SDavid du Colombier 		ctlr->rx[i].num = i - 1;
566*5c47fe09SDavid du Colombier 		rcfg |= 1<<(i-1);
567*5c47fe09SDavid du Colombier 	}
568*5c47fe09SDavid du Colombier 	assert(rcfg && (rcfg & ~RxRingCfgMask) == 0);
569*5c47fe09SDavid du Colombier 
570*5c47fe09SDavid du Colombier 	ctlr->tx->intregs = &ctlr->regs[Intrl0];
571*5c47fe09SDavid du Colombier 	ctlr->tx->intmask = IrqTxDmaDone;
572*5c47fe09SDavid du Colombier 	ctlr->tx->num = 16;
573*5c47fe09SDavid du Colombier 	tcfg = 1<<16;
574*5c47fe09SDavid du Colombier 	for(i = 1; i < nelem(ctlr->tx); i++){
575*5c47fe09SDavid du Colombier 		ctlr->tx[i].regs = &ctlr->regs[TdmaOffset + nelem(ctlr->td)*3 + (i-1)*RingCfg];
576*5c47fe09SDavid du Colombier 		ctlr->tx[i].intregs = &ctlr->regs[Intrl1];
577*5c47fe09SDavid du Colombier 		ctlr->tx[i].intmask = 1 << (i - 1);
578*5c47fe09SDavid du Colombier 		ctlr->tx[i].num = i - 1;
579*5c47fe09SDavid du Colombier 		tcfg |= 1<<(i-1);
580*5c47fe09SDavid du Colombier 	}
581*5c47fe09SDavid du Colombier 	assert(tcfg && (tcfg & ~TxRingCfgMask) == 0);
582*5c47fe09SDavid du Colombier 
583*5c47fe09SDavid du Colombier 	REG(ctlr->rx->regs[DmaScbBurstSize]) = 0x08;
584*5c47fe09SDavid du Colombier 	for(i = 1; i < nelem(ctlr->rx); i++)
585*5c47fe09SDavid du Colombier 		initring(&ctlr->rx[i], ctlr->rd, (i-1)*32, 32);
586*5c47fe09SDavid du Colombier 	initring(ctlr->rx, ctlr->rd, (i-1)*32, nelem(ctlr->rd) - (i-1)*32);
587*5c47fe09SDavid du Colombier 
588*5c47fe09SDavid du Colombier 	for(i = 0; i < nelem(ctlr->rx); i++){
589*5c47fe09SDavid du Colombier 		REG(ctlr->rx[i].regs[DmaDoneThresh]) = 1;
590*5c47fe09SDavid du Colombier 		REG(ctlr->rx[i].regs[RdmaXonXoffThresh]) = (5 << 16) | ((ctlr->rx[i].m+1) >> 4);
591*5c47fe09SDavid du Colombier 
592*5c47fe09SDavid du Colombier 		// set dma timeout to 50µs
593*5c47fe09SDavid du Colombier 		REG(ctlr->rx->regs[RdmaTimeout0 + ctlr->rx[i].num]) = ((50*1000 + 8191)/8192);
594*5c47fe09SDavid du Colombier 	}
595*5c47fe09SDavid du Colombier 
596*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[DmaScbBurstSize]) = 0x08;
597*5c47fe09SDavid du Colombier 	for(i = 1; i < nelem(ctlr->tx); i++)
598*5c47fe09SDavid du Colombier 		initring(&ctlr->tx[i], ctlr->td, (i-1)*32, 32);
599*5c47fe09SDavid du Colombier 	initring(ctlr->tx, ctlr->td, (i-1)*32, nelem(ctlr->td) - (i-1)*32);
600*5c47fe09SDavid du Colombier 
601*5c47fe09SDavid du Colombier 	dmapri[0] = dmapri[1] = dmapri[2] = 0;
602*5c47fe09SDavid du Colombier 	for(i = 0; i < nelem(ctlr->tx); i++){
603*5c47fe09SDavid du Colombier 		REG(ctlr->tx[i].regs[DmaDoneThresh]) = 10;
604*5c47fe09SDavid du Colombier 		REG(ctlr->tx[i].regs[TdmaFlowPeriod]) = i ? 0 : Maxtu << 16;
605*5c47fe09SDavid du Colombier 		dmapri[ctlr->tx[i].num/6] |= i << ((ctlr->tx[i].num%6)*5);
606*5c47fe09SDavid du Colombier 	}
607*5c47fe09SDavid du Colombier 
608*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[TdmaArbCtrl]) = 2;
609*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[TdmaPriority0]) = dmapri[0];
610*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[TdmaPriority1]) = dmapri[1];
611*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[TdmaPriority2]) = dmapri[2];
612*5c47fe09SDavid du Colombier 
613*5c47fe09SDavid du Colombier 	REG(ctlr->rx->regs[RingCfg]) = rcfg;
614*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[RingCfg]) = tcfg;
615*5c47fe09SDavid du Colombier 
616*5c47fe09SDavid du Colombier 	REG(ctlr->rx->regs[DmaCtrl]) |= rcfg<<1;
617*5c47fe09SDavid du Colombier 	REG(ctlr->tx->regs[DmaCtrl]) |= tcfg<<1;
618*5c47fe09SDavid du Colombier }
619*5c47fe09SDavid du Colombier 
620*5c47fe09SDavid du Colombier static void
umaccmd(Ctlr * ctlr,u32int set,u32int clr)621*5c47fe09SDavid du Colombier umaccmd(Ctlr *ctlr, u32int set, u32int clr)
622*5c47fe09SDavid du Colombier {
623*5c47fe09SDavid du Colombier 	ilock(ctlr);
624*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacCmd]) = (REG(ctlr->regs[UmacCmd]) & ~clr) | set;
625*5c47fe09SDavid du Colombier 	iunlock(ctlr);
626*5c47fe09SDavid du Colombier }
627*5c47fe09SDavid du Colombier 
628*5c47fe09SDavid du Colombier static void
reset(Ctlr * ctlr)629*5c47fe09SDavid du Colombier reset(Ctlr *ctlr)
630*5c47fe09SDavid du Colombier {
631*5c47fe09SDavid du Colombier 	u32int r;
632*5c47fe09SDavid du Colombier 
633*5c47fe09SDavid du Colombier 	// reset umac
634*5c47fe09SDavid du Colombier 	r = REG(ctlr->regs[SysRbufFlushCtrl]);
635*5c47fe09SDavid du Colombier 	REG(ctlr->regs[SysRbufFlushCtrl]) = r | 2;
636*5c47fe09SDavid du Colombier 	microdelay(10);
637*5c47fe09SDavid du Colombier 	REG(ctlr->regs[SysRbufFlushCtrl]) = r & ~2;
638*5c47fe09SDavid du Colombier 	microdelay(10);
639*5c47fe09SDavid du Colombier 
640*5c47fe09SDavid du Colombier 	// umac reset
641*5c47fe09SDavid du Colombier 	REG(ctlr->regs[SysRbufFlushCtrl]) = 0;
642*5c47fe09SDavid du Colombier 	microdelay(10);
643*5c47fe09SDavid du Colombier 
644*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacCmd]) = 0;
645*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacCmd]) = CmdSwReset | CmdLclLoopEn;
646*5c47fe09SDavid du Colombier 	microdelay(2);
647*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacCmd]) = 0;
648*5c47fe09SDavid du Colombier }
649*5c47fe09SDavid du Colombier 
650*5c47fe09SDavid du Colombier static void
setmac(Ctlr * ctlr,uchar * ea)651*5c47fe09SDavid du Colombier setmac(Ctlr *ctlr, uchar *ea)
652*5c47fe09SDavid du Colombier {
653*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMac0]) = ea[0]<<24 | ea[1]<<16 | ea[2]<<8 | ea[3];
654*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMac1]) = ea[4]<<8 | ea[5];
655*5c47fe09SDavid du Colombier }
656*5c47fe09SDavid du Colombier 
657*5c47fe09SDavid du Colombier static void
sethfb(Ctlr * ctlr)658*5c47fe09SDavid du Colombier sethfb(Ctlr *ctlr)
659*5c47fe09SDavid du Colombier {
660*5c47fe09SDavid du Colombier 	int i;
661*5c47fe09SDavid du Colombier 
662*5c47fe09SDavid du Colombier 	REG(ctlr->regs[HfbCtlr]) = 0;
663*5c47fe09SDavid du Colombier 	REG(ctlr->regs[HfbFltEnable]) = 0;
664*5c47fe09SDavid du Colombier 	REG(ctlr->regs[HfbFltEnable+1]) = 0;
665*5c47fe09SDavid du Colombier 
666*5c47fe09SDavid du Colombier 	for(i = 0; i < 8; i++)
667*5c47fe09SDavid du Colombier 		REG(ctlr->rx->regs[RdmaIndex2Ring0+i]) = 0;
668*5c47fe09SDavid du Colombier 
669*5c47fe09SDavid du Colombier 	for(i = 0; i < 48/4; i++)
670*5c47fe09SDavid du Colombier 		REG(ctlr->regs[HfbFltLen + i]) = 0;
671*5c47fe09SDavid du Colombier 
672*5c47fe09SDavid du Colombier 	for(i = 0; i < 48*128; i++)
673*5c47fe09SDavid du Colombier 		REG(ctlr->regs[HfbOffset + i]) = 0;
674*5c47fe09SDavid du Colombier }
675*5c47fe09SDavid du Colombier 
676*5c47fe09SDavid du Colombier static int
mdiodone(void * arg)677*5c47fe09SDavid du Colombier mdiodone(void *arg)
678*5c47fe09SDavid du Colombier {
679*5c47fe09SDavid du Colombier 	Ctlr *ctlr = arg;
680*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl0 + IntrMaskClr]) = (IrqMdioDone|IrqMdioError);
681*5c47fe09SDavid du Colombier 	return (REG(ctlr->regs[MdioCmd]) & MdioStartBusy) == 0;
682*5c47fe09SDavid du Colombier }
683*5c47fe09SDavid du Colombier 
684*5c47fe09SDavid du Colombier static int
mdiowait(Ctlr * ctlr)685*5c47fe09SDavid du Colombier mdiowait(Ctlr *ctlr)
686*5c47fe09SDavid du Colombier {
687*5c47fe09SDavid du Colombier 	REG(ctlr->regs[MdioCmd]) |= MdioStartBusy;
688*5c47fe09SDavid du Colombier 	while(REG(ctlr->regs[MdioCmd]) & MdioStartBusy)
689*5c47fe09SDavid du Colombier 		tsleep(ctlr->mii, mdiodone, ctlr, 10);
690*5c47fe09SDavid du Colombier 	return 0;
691*5c47fe09SDavid du Colombier }
692*5c47fe09SDavid du Colombier 
693*5c47fe09SDavid du Colombier static int
mdiow(Mii * mii,int phy,int addr,int data)694*5c47fe09SDavid du Colombier mdiow(Mii* mii, int phy, int addr, int data)
695*5c47fe09SDavid du Colombier {
696*5c47fe09SDavid du Colombier 	Ctlr *ctlr = mii->ctlr;
697*5c47fe09SDavid du Colombier 
698*5c47fe09SDavid du Colombier 	if(phy > MdioPhyMask)
699*5c47fe09SDavid du Colombier 		return -1;
700*5c47fe09SDavid du Colombier 	addr &= MdioAddrMask;
701*5c47fe09SDavid du Colombier 	REG(ctlr->regs[MdioCmd]) = MdioWrite
702*5c47fe09SDavid du Colombier 		| (phy << MdioPhyShift) | (addr << MdioAddrShift) | (data & 0xFFFF);
703*5c47fe09SDavid du Colombier 	return mdiowait(ctlr);
704*5c47fe09SDavid du Colombier }
705*5c47fe09SDavid du Colombier 
706*5c47fe09SDavid du Colombier static int
mdior(Mii * mii,int phy,int addr)707*5c47fe09SDavid du Colombier mdior(Mii* mii, int phy, int addr)
708*5c47fe09SDavid du Colombier {
709*5c47fe09SDavid du Colombier 	Ctlr *ctlr = mii->ctlr;
710*5c47fe09SDavid du Colombier 
711*5c47fe09SDavid du Colombier 	if(phy > MdioPhyMask)
712*5c47fe09SDavid du Colombier 		return -1;
713*5c47fe09SDavid du Colombier 	addr &= MdioAddrMask;
714*5c47fe09SDavid du Colombier 	REG(ctlr->regs[MdioCmd]) = MdioRead
715*5c47fe09SDavid du Colombier 		| (phy << MdioPhyShift) | (addr << MdioAddrShift);
716*5c47fe09SDavid du Colombier 	if(mdiowait(ctlr) < 0)
717*5c47fe09SDavid du Colombier 		return -1;
718*5c47fe09SDavid du Colombier 	if(REG(ctlr->regs[MdioCmd]) & MdioReadFail)
719*5c47fe09SDavid du Colombier 		return -1;
720*5c47fe09SDavid du Colombier 	return REG(ctlr->regs[MdioCmd]) & 0xFFFF;
721*5c47fe09SDavid du Colombier }
722*5c47fe09SDavid du Colombier 
723*5c47fe09SDavid du Colombier static int
bcmshdr(Mii * mii,int reg)724*5c47fe09SDavid du Colombier bcmshdr(Mii *mii, int reg)
725*5c47fe09SDavid du Colombier {
726*5c47fe09SDavid du Colombier 	miimiw(mii, 0x1C, (reg & 0x1F) << 10);
727*5c47fe09SDavid du Colombier 	return miimir(mii, 0x1C) & 0x3FF;
728*5c47fe09SDavid du Colombier }
729*5c47fe09SDavid du Colombier 
730*5c47fe09SDavid du Colombier static int
bcmshdw(Mii * mii,int reg,int dat)731*5c47fe09SDavid du Colombier bcmshdw(Mii *mii, int reg, int dat)
732*5c47fe09SDavid du Colombier {
733*5c47fe09SDavid du Colombier 	return miimiw(mii, 0x1C, 0x8000 | (reg & 0x1F) << 10 | (dat & 0x3FF));
734*5c47fe09SDavid du Colombier }
735*5c47fe09SDavid du Colombier 
736*5c47fe09SDavid du Colombier static int
linkevent(void * arg)737*5c47fe09SDavid du Colombier linkevent(void *arg)
738*5c47fe09SDavid du Colombier {
739*5c47fe09SDavid du Colombier 	Ctlr *ctlr = arg;
740*5c47fe09SDavid du Colombier 	REG(ctlr->regs[Intrl0 + IntrMaskClr]) = IrqLinkUp|IrqLinkDown;
741*5c47fe09SDavid du Colombier 	return 0;
742*5c47fe09SDavid du Colombier }
743*5c47fe09SDavid du Colombier 
744*5c47fe09SDavid du Colombier static void
linkproc(void * arg)745*5c47fe09SDavid du Colombier linkproc(void *arg)
746*5c47fe09SDavid du Colombier {
747*5c47fe09SDavid du Colombier 	Ether *edev = arg;
748*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
749*5c47fe09SDavid du Colombier 	MiiPhy *phy;
750*5c47fe09SDavid du Colombier 	int link = -1;
751*5c47fe09SDavid du Colombier 
752*5c47fe09SDavid du Colombier 	while(waserror())
753*5c47fe09SDavid du Colombier 		;
754*5c47fe09SDavid du Colombier 
755*5c47fe09SDavid du Colombier 	for(;;){
756*5c47fe09SDavid du Colombier 		tsleep(ctlr->link, linkevent, ctlr, 1000);
757*5c47fe09SDavid du Colombier 		miistatus(ctlr->mii);
758*5c47fe09SDavid du Colombier 		phy = ctlr->mii->curphy;
759*5c47fe09SDavid du Colombier 		if(phy == nil || phy->link == link)
760*5c47fe09SDavid du Colombier 			continue;
761*5c47fe09SDavid du Colombier 		link = phy->link;
762*5c47fe09SDavid du Colombier 		if(link){
763*5c47fe09SDavid du Colombier 			u32int cmd = CmdRxEn|CmdTxEn;
764*5c47fe09SDavid du Colombier 			switch(phy->speed){
765*5c47fe09SDavid du Colombier 			case 1000:	cmd |= CmdSpeed1000; break;
766*5c47fe09SDavid du Colombier 			case 100:	cmd |= CmdSpeed100; break;
767*5c47fe09SDavid du Colombier 			case 10:	cmd |= CmdSpeed10; break;
768*5c47fe09SDavid du Colombier 			}
769*5c47fe09SDavid du Colombier 			if(!phy->fd)
770*5c47fe09SDavid du Colombier 				cmd |= CmdHdEn;
771*5c47fe09SDavid du Colombier 			if(!phy->rfc)
772*5c47fe09SDavid du Colombier 				cmd |= CmdRxPauseIgn;
773*5c47fe09SDavid du Colombier 			if(!phy->tfc)
774*5c47fe09SDavid du Colombier 				cmd |= CmdTxPauseIgn;
775*5c47fe09SDavid du Colombier 
776*5c47fe09SDavid du Colombier 			REG(ctlr->regs[ExtRgmiiOobCtrl]) = (REG(ctlr->regs[ExtRgmiiOobCtrl]) & ~OobDisable) | RgmiiLink;
777*5c47fe09SDavid du Colombier 			umaccmd(ctlr, cmd, CmdSpeedMask|CmdHdEn|CmdRxPauseIgn|CmdTxPauseIgn);
778*5c47fe09SDavid du Colombier 
779*5c47fe09SDavid du Colombier 			edev->mbps = phy->speed;
780*5c47fe09SDavid du Colombier 		}
781*5c47fe09SDavid du Colombier 		edev->link = link;
782*5c47fe09SDavid du Colombier 		// print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps);
783*5c47fe09SDavid du Colombier 	}
784*5c47fe09SDavid du Colombier }
785*5c47fe09SDavid du Colombier 
786*5c47fe09SDavid du Colombier static void
setmdfaddr(Ctlr * ctlr,int i,uchar * ea)787*5c47fe09SDavid du Colombier setmdfaddr(Ctlr *ctlr, int i, uchar *ea)
788*5c47fe09SDavid du Colombier {
789*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMdfAddr0 + i*2 + 0]) = ea[0] << 8  | ea[1];
790*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMdfAddr0 + i*2 + 1]) = ea[2] << 24 | ea[3] << 16 | ea[4] << 8 | ea[5];
791*5c47fe09SDavid du Colombier }
792*5c47fe09SDavid du Colombier 
793*5c47fe09SDavid du Colombier static void
rxmode(Ether * edev,int prom)794*5c47fe09SDavid du Colombier rxmode(Ether *edev, int prom)
795*5c47fe09SDavid du Colombier {
796*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
797*5c47fe09SDavid du Colombier 	Netaddr *na;
798*5c47fe09SDavid du Colombier 	int i;
799*5c47fe09SDavid du Colombier 
800*5c47fe09SDavid du Colombier 	if(prom || edev->nmaddr > 16-2){
801*5c47fe09SDavid du Colombier 		REG(ctlr->regs[UmacMdfCtrl]) = 0;
802*5c47fe09SDavid du Colombier 		umaccmd(ctlr, CmdProm, 0);
803*5c47fe09SDavid du Colombier 		return;
804*5c47fe09SDavid du Colombier 	}
805*5c47fe09SDavid du Colombier 	setmdfaddr(ctlr, 0, edev->bcast);
806*5c47fe09SDavid du Colombier 	setmdfaddr(ctlr, 1, edev->ea);
807*5c47fe09SDavid du Colombier 	for(i = 2, na = edev->maddr; na != nil; na = na->next, i++)
808*5c47fe09SDavid du Colombier 		setmdfaddr(ctlr, i, na->addr);
809*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMdfCtrl]) = (-0x10000 >> i) & 0x1FFFF;
810*5c47fe09SDavid du Colombier 	umaccmd(ctlr, 0, CmdProm);
811*5c47fe09SDavid du Colombier }
812*5c47fe09SDavid du Colombier 
813*5c47fe09SDavid du Colombier static void
shutdown(Ether * edev)814*5c47fe09SDavid du Colombier shutdown(Ether *edev)
815*5c47fe09SDavid du Colombier {
816*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
817*5c47fe09SDavid du Colombier 
818*5c47fe09SDavid du Colombier 	dmaoff(ctlr);
819*5c47fe09SDavid du Colombier 	introff(ctlr);
820*5c47fe09SDavid du Colombier }
821*5c47fe09SDavid du Colombier 
822*5c47fe09SDavid du Colombier static void
attach(Ether * edev)823*5c47fe09SDavid du Colombier attach(Ether *edev)
824*5c47fe09SDavid du Colombier {
825*5c47fe09SDavid du Colombier 	Ctlr *ctlr = edev->ctlr;
826*5c47fe09SDavid du Colombier 
827*5c47fe09SDavid du Colombier 	qlock(ctlr);
828*5c47fe09SDavid du Colombier 	if(ctlr->attached){
829*5c47fe09SDavid du Colombier 		qunlock(ctlr);
830*5c47fe09SDavid du Colombier 		return;
831*5c47fe09SDavid du Colombier 	}
832*5c47fe09SDavid du Colombier 	if(waserror()){
833*5c47fe09SDavid du Colombier 		print("#l%d: %s\n", edev->ctlrno, up->errstr);
834*5c47fe09SDavid du Colombier 		shutdown(edev);
835*5c47fe09SDavid du Colombier 		freebufs(ctlr);
836*5c47fe09SDavid du Colombier 		qunlock(ctlr);
837*5c47fe09SDavid du Colombier 		nexterror();
838*5c47fe09SDavid du Colombier 	}
839*5c47fe09SDavid du Colombier 
840*5c47fe09SDavid du Colombier 	// statistics
841*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMibCtrl]) = MibResetRx | MibResetTx | MibResetRunt;
842*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMibCtrl]) = 0;
843*5c47fe09SDavid du Colombier 
844*5c47fe09SDavid du Colombier 	// wol
845*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMpdCtrl]) &= ~(MpdPwEn|MpdEn);
846*5c47fe09SDavid du Colombier 
847*5c47fe09SDavid du Colombier 	// power
848*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacEeeCtrl]) &= ~UmacEeeEn;
849*5c47fe09SDavid du Colombier 	REG(ctlr->regs[RbufEnergyCtrl]) &= ~(RbufEeeEn|RbufPmEn);
850*5c47fe09SDavid du Colombier 	REG(ctlr->regs[TbufEnergyCtrl]) &= ~(RbufEeeEn|RbufPmEn);
851*5c47fe09SDavid du Colombier 	REG(ctlr->regs[TbufBpMc]) = 0;
852*5c47fe09SDavid du Colombier 
853*5c47fe09SDavid du Colombier 	REG(ctlr->regs[UmacMaxFrameLen]) = Maxtu;
854*5c47fe09SDavid du Colombier 
855*5c47fe09SDavid du Colombier 	REG(ctlr->regs[RbufTbufSizeCtrl]) = 1;
856*5c47fe09SDavid du Colombier 
857*5c47fe09SDavid du Colombier 	REG(ctlr->regs[TbufCtrl]) &= ~(Rbuf64En);
858*5c47fe09SDavid du Colombier 	REG(ctlr->regs[RbufCtrl]) &= ~(Rbuf64En|RbufAlign2B);
859*5c47fe09SDavid du Colombier 	REG(ctlr->regs[RbufChkCtrl]) &= ~(RbufChkRxChkEn|RbufChkSkipFcs);
860*5c47fe09SDavid du Colombier 
861*5c47fe09SDavid du Colombier 	allocbufs(ctlr);
862*5c47fe09SDavid du Colombier 	initrings(ctlr);
863*5c47fe09SDavid du Colombier 	dmaon(ctlr);
864*5c47fe09SDavid du Colombier 
865*5c47fe09SDavid du Colombier 	setmac(ctlr, edev->ea);
866*5c47fe09SDavid du Colombier 	sethfb(ctlr);
867*5c47fe09SDavid du Colombier 	rxmode(edev, 0);
868*5c47fe09SDavid du Colombier 
869*5c47fe09SDavid du Colombier 	REG(ctlr->regs[SysPortCtrl]) = PortModeExtGphy;
870*5c47fe09SDavid du Colombier 	REG(ctlr->regs[ExtRgmiiOobCtrl]) |= RgmiiModeEn | IdModeDis;
871*5c47fe09SDavid du Colombier 
872*5c47fe09SDavid du Colombier 	ctlr->mii->ctlr = ctlr;
873*5c47fe09SDavid du Colombier 	ctlr->mii->mir = mdior;
874*5c47fe09SDavid du Colombier 	ctlr->mii->miw = mdiow;
875*5c47fe09SDavid du Colombier 	mii(ctlr->mii, ~0);
876*5c47fe09SDavid du Colombier 
877*5c47fe09SDavid du Colombier 	if(ctlr->mii->curphy == nil)
878*5c47fe09SDavid du Colombier 		error("no phy");
879*5c47fe09SDavid du Colombier 
880*5c47fe09SDavid du Colombier 	MIIDBG("#l%d: phy%d id %.8ux oui %x\n",
881*5c47fe09SDavid du Colombier 		edev->ctlrno, ctlr->mii->curphy->phyno,
882*5c47fe09SDavid du Colombier 		ctlr->mii->curphy->id, ctlr->mii->curphy->oui);
883*5c47fe09SDavid du Colombier 
884*5c47fe09SDavid du Colombier 	miireset(ctlr->mii);
885*5c47fe09SDavid du Colombier 
886*5c47fe09SDavid du Colombier 	switch(ctlr->mii->curphy->id){
887*5c47fe09SDavid du Colombier 	case 0x600d84a2:	/* BCM54312PE */
888*5c47fe09SDavid du Colombier 		/* mask interrupts */
889*5c47fe09SDavid du Colombier 		miimiw(ctlr->mii, 0x10, miimir(ctlr->mii, 0x10) | 0x1000);
890*5c47fe09SDavid du Colombier 
891*5c47fe09SDavid du Colombier 		/* SCR3: clear DLLAPD_DIS */
892*5c47fe09SDavid du Colombier 		bcmshdw(ctlr->mii, 0x05, bcmshdr(ctlr->mii, 0x05) &~0x0002);
893*5c47fe09SDavid du Colombier 		/* APD: set APD_EN */
894*5c47fe09SDavid du Colombier 		bcmshdw(ctlr->mii, 0x0a, bcmshdr(ctlr->mii, 0x0a) | 0x0020);
895*5c47fe09SDavid du Colombier 
896*5c47fe09SDavid du Colombier 		/* blinkenlights */
897*5c47fe09SDavid du Colombier 		bcmshdw(ctlr->mii, 0x09, bcmshdr(ctlr->mii, 0x09) | 0x0010);
898*5c47fe09SDavid du Colombier 		bcmshdw(ctlr->mii, 0x0d, 3<<0 | 0<<4);
899*5c47fe09SDavid du Colombier 		break;
900*5c47fe09SDavid du Colombier 	}
901*5c47fe09SDavid du Colombier 
902*5c47fe09SDavid du Colombier 	/* don't advertise EEE */
903*5c47fe09SDavid du Colombier 	miimmdw(ctlr->mii, 7, 60, 0);
904*5c47fe09SDavid du Colombier 
905*5c47fe09SDavid du Colombier 	miiane(ctlr->mii, ~0, AnaAP|AnaP, ~0);
906*5c47fe09SDavid du Colombier 
907*5c47fe09SDavid du Colombier 	ctlr->attached = 1;
908*5c47fe09SDavid du Colombier 
909*5c47fe09SDavid du Colombier 	kproc("genet-recv", recvproc, edev);
910*5c47fe09SDavid du Colombier 	kproc("genet-send", sendproc, edev);
911*5c47fe09SDavid du Colombier 	kproc("genet-free", freeproc, edev);
912*5c47fe09SDavid du Colombier 	kproc("genet-link", linkproc, edev);
913*5c47fe09SDavid du Colombier 
914*5c47fe09SDavid du Colombier 	qunlock(ctlr);
915*5c47fe09SDavid du Colombier 	poperror();
916*5c47fe09SDavid du Colombier }
917*5c47fe09SDavid du Colombier 
918*5c47fe09SDavid du Colombier static void
prom(void * arg,int on)919*5c47fe09SDavid du Colombier prom(void *arg, int on)
920*5c47fe09SDavid du Colombier {
921*5c47fe09SDavid du Colombier 	Ether *edev = arg;
922*5c47fe09SDavid du Colombier 	rxmode(edev, on);
923*5c47fe09SDavid du Colombier }
924*5c47fe09SDavid du Colombier 
925*5c47fe09SDavid du Colombier static void
multi(void * arg,uchar *,int)926*5c47fe09SDavid du Colombier multi(void *arg, uchar*, int)
927*5c47fe09SDavid du Colombier {
928*5c47fe09SDavid du Colombier 	Ether *edev = arg;
929*5c47fe09SDavid du Colombier 	rxmode(edev, edev->prom > 0);
930*5c47fe09SDavid du Colombier }
931*5c47fe09SDavid du Colombier 
932*5c47fe09SDavid du Colombier static int
pnp(Ether * edev)933*5c47fe09SDavid du Colombier pnp(Ether *edev)
934*5c47fe09SDavid du Colombier {
935*5c47fe09SDavid du Colombier 	static Ctlr ctlr[1];
936*5c47fe09SDavid du Colombier 
937*5c47fe09SDavid du Colombier 	if(ctlr->regs != nil)
938*5c47fe09SDavid du Colombier 		return -1;
939*5c47fe09SDavid du Colombier 
940*5c47fe09SDavid du Colombier 	ctlr->regs = (u32int*)(VIRTIO + 0x580000);
941*5c47fe09SDavid du Colombier 	ctlr->rx->regs = &ctlr->regs[RdmaOffset + nelem(ctlr->rd)*3 + 16*RingCfg];
942*5c47fe09SDavid du Colombier 	ctlr->tx->regs = &ctlr->regs[TdmaOffset + nelem(ctlr->td)*3 + 16*RingCfg];
943*5c47fe09SDavid du Colombier 
944*5c47fe09SDavid du Colombier 	edev->port = (uintptr)ctlr->regs;
945*5c47fe09SDavid du Colombier 	edev->irq = IRQether;
946*5c47fe09SDavid du Colombier 	edev->ctlr = ctlr;
947*5c47fe09SDavid du Colombier 	edev->attach = attach;
948*5c47fe09SDavid du Colombier 	edev->shutdown = shutdown;
949*5c47fe09SDavid du Colombier 	edev->promiscuous = prom;
950*5c47fe09SDavid du Colombier 	edev->multicast = multi;
951*5c47fe09SDavid du Colombier 	edev->arg = edev;
952*5c47fe09SDavid du Colombier 	edev->mbps = 1000;
953*5c47fe09SDavid du Colombier 	edev->maxmtu = Maxtu;
954*5c47fe09SDavid du Colombier 
955*5c47fe09SDavid du Colombier 	parseether(edev->ea, getethermac());
956*5c47fe09SDavid du Colombier 
957*5c47fe09SDavid du Colombier 	reset(ctlr);
958*5c47fe09SDavid du Colombier 	dmaoff(ctlr);
959*5c47fe09SDavid du Colombier 	introff(ctlr);
960*5c47fe09SDavid du Colombier 
961*5c47fe09SDavid du Colombier 	intrenable(edev->irq+0, interrupt0, edev, BUSUNKNOWN, edev->name);
962*5c47fe09SDavid du Colombier 	intrenable(edev->irq+1, interrupt1, edev, BUSUNKNOWN, edev->name);
963*5c47fe09SDavid du Colombier 
964*5c47fe09SDavid du Colombier 	return 0;
965*5c47fe09SDavid du Colombier }
966*5c47fe09SDavid du Colombier 
967*5c47fe09SDavid du Colombier void
ethergenetlink(void)968*5c47fe09SDavid du Colombier ethergenetlink(void)
969*5c47fe09SDavid du Colombier {
970*5c47fe09SDavid du Colombier 	addethercard("genet", pnp);
971*5c47fe09SDavid du Colombier }
972