xref: /plan9-contrib/sys/src/boot/vt4/ethertemac.c (revision da917039c7f233c1a27d212bf012c6afa758af39)
1*da917039SDavid du Colombier /*
2*da917039SDavid du Colombier  * Xilinx Temacs Ethernet driver.
3*da917039SDavid du Colombier  * It uses the Local Link FIFOs.
4*da917039SDavid du Colombier  * There are two interfaces per Temacs controller.
5*da917039SDavid du Colombier  * Half-duplex is not supported by hardware.
6*da917039SDavid du Colombier  */
7*da917039SDavid du Colombier #include "include.h"
8*da917039SDavid du Colombier 
9*da917039SDavid du Colombier enum {
10*da917039SDavid du Colombier 	/* fixed by hardware */
11*da917039SDavid du Colombier 	Nifcs = 2,
12*da917039SDavid du Colombier 
13*da917039SDavid du Colombier 	/* tunable parameters; see below for more */
14*da917039SDavid du Colombier 	Nrde = 64,
15*da917039SDavid du Colombier 	Ntde = 4,
16*da917039SDavid du Colombier };
17*da917039SDavid du Colombier enum {				/* directly-addressible registers' bits */
18*da917039SDavid du Colombier 	/* raf register */
19*da917039SDavid du Colombier 	Htrst	= 1<<0,		/* hard temac reset (both ifcs) */
20*da917039SDavid du Colombier 	Mcstrej	= 1<<1,		/* reject received multicast dest addr */
21*da917039SDavid du Colombier 	Bcstrej	= 1<<2,		/* reject received broadcast dest addr */
22*da917039SDavid du Colombier 
23*da917039SDavid du Colombier 	/* is, ip, ie register */
24*da917039SDavid du Colombier 	Hardacscmplt = 1<<0,	/* hard register access complete */
25*da917039SDavid du Colombier 	Autoneg	= 1<<1,		/* auto-negotiation complete */
26*da917039SDavid du Colombier 	Rxcmplt	= 1<<2,		/* receive complete */
27*da917039SDavid du Colombier 	Rxrject	= 1<<3,		/* receive frame rejected */
28*da917039SDavid du Colombier 	Rxfifoovr = 1<<4,	/* receive fifo overrun */
29*da917039SDavid du Colombier 	Txcmplt	= 1<<5,		/* transmit complete */
30*da917039SDavid du Colombier 	Rxdcmlock = 1<<6,	/* receive DCM lock (ready for use) */
31*da917039SDavid du Colombier 	Mgtrdy	= 1<<7,		/* mgt ready (new in 1.01b)
32*da917039SDavid du Colombier 
33*da917039SDavid du Colombier 	/* ctl register */
34*da917039SDavid du Colombier 	Wen	= 1<<15,	/* write instead of read */
35*da917039SDavid du Colombier 
36*da917039SDavid du Colombier 	/* ctl register address codes; select other registers */
37*da917039SDavid du Colombier 	Rcw0	= 0x200,	/* receive configuration */
38*da917039SDavid du Colombier 	Rcw1	= 0x240,
39*da917039SDavid du Colombier 	Tc	= 0x280,	/* tx config */
40*da917039SDavid du Colombier 	Fcc	= 0x2c0,	/* flow control */
41*da917039SDavid du Colombier 	Emmc	= 0x300,	/* ethernet mac mode config */
42*da917039SDavid du Colombier 	Phyc	= 0x320,	/* rgmii/sgmii config */
43*da917039SDavid du Colombier 	Mc	= 0x340,	/* mgmt config */
44*da917039SDavid du Colombier 	Uaw0	= 0x380,	/* unicast addr word 0 (low-order) */
45*da917039SDavid du Colombier 	Uaw1	= 0x384,	/* unicast addr word 1 (high-order) */
46*da917039SDavid du Colombier 	Maw0	= 0x388,	/* multicast addr word 0 (low) */
47*da917039SDavid du Colombier 	Maw1	= 0x38c,	/* multicast addr word 1 (high + more) */
48*da917039SDavid du Colombier 	Afm	= 0x390,	/* addr filter mode */
49*da917039SDavid du Colombier 	Tis	= 0x3a0,	/* intr status */
50*da917039SDavid du Colombier 	Tie	= 0x3a4,	/* intr enable */
51*da917039SDavid du Colombier 	Miimwd	= 0x3b0,	/* mii mgmt write data */
52*da917039SDavid du Colombier 	Miimai	= 0x3b4,	/* mii mgmt access initiate */
53*da917039SDavid du Colombier 
54*da917039SDavid du Colombier 	/* rdy register */
55*da917039SDavid du Colombier 	Fabrrr	= 1<<0,		/* fabric read ready */
56*da917039SDavid du Colombier 	Miimrr	= 1<<1,		/* mii mgmt read ready */
57*da917039SDavid du Colombier 	Miimwr	= 1<<2,		/* mii mgmt write ready */
58*da917039SDavid du Colombier 	Afrr	= 1<<3,		/* addr filter read ready */
59*da917039SDavid du Colombier 	Afwr	= 1<<4,		/* addr filter write ready */
60*da917039SDavid du Colombier 	Cfgrr	= 1<<5,		/* config reg read ready */
61*da917039SDavid du Colombier 	Cfgwr	= 1<<6,		/* config reg write ready */
62*da917039SDavid du Colombier 	Hardacsrdy = 1<<16,	/* hard reg access ready */
63*da917039SDavid du Colombier };
64*da917039SDavid du Colombier enum {				/* indirectly-addressible registers' bits */
65*da917039SDavid du Colombier 	/* Rcw1 register */
66*da917039SDavid du Colombier 	Rst	= 1<<31,	/* reset */
67*da917039SDavid du Colombier 	Jum	= 1<<30,	/* jumbo frame enable */
68*da917039SDavid du Colombier 	Fcs	= 1<<29,	/* in-band fcs enable */
69*da917039SDavid du Colombier 	Rx	= 1<<28,	/* rx enable */
70*da917039SDavid du Colombier 	Vlan	= 1<<27,	/* vlan frame enable */
71*da917039SDavid du Colombier 	Hd	= 1<<26,	/* half-duplex mode (must be 0) */
72*da917039SDavid du Colombier 	Ltdis	= 1<<25,	/* length/type field valid check disable */
73*da917039SDavid du Colombier 
74*da917039SDavid du Colombier 	/* Tc register.  same as Rcw1 but Rx->Tx, Ltdis->Ifg */
75*da917039SDavid du Colombier 	Tx	= Rx,		/* tx enable */
76*da917039SDavid du Colombier 	Ifg	= Ltdis,	/* inter-frame gap adjustment enable */
77*da917039SDavid du Colombier 
78*da917039SDavid du Colombier 	/* Fcc register */
79*da917039SDavid du Colombier 	Fctx	= 1<<30,	/* tx flow control enable */
80*da917039SDavid du Colombier 	Fcrx	= 1<<29,	/* rx flow control enable */
81*da917039SDavid du Colombier 
82*da917039SDavid du Colombier 	/* Emmc register */
83*da917039SDavid du Colombier 	Linkspeed = 3<<30,	/* field */
84*da917039SDavid du Colombier 	Ls1000	= 2<<30,	/* Gb */
85*da917039SDavid du Colombier 	Ls100	= 1<<30,	/* 100Mb */
86*da917039SDavid du Colombier 	Ls10	= 0<<30,	/* 10Mb */
87*da917039SDavid du Colombier 	Rgmii	= 1<<29,	/* rgmii mode enable */
88*da917039SDavid du Colombier 	Sgmii	= 1<<28,	/* sgmii mode enable */
89*da917039SDavid du Colombier 	Gpcs	= 1<<27,	/* 1000base-x mode enable */
90*da917039SDavid du Colombier 	Hostifen= 1<<26,	/* host interface enable */
91*da917039SDavid du Colombier 	Tx16	= 1<<25,	/* tx 16-bit (vs 8-bit) data ifc enable (0) */
92*da917039SDavid du Colombier 	Rx16	= 1<<24,	/* rx 16-bit (vs 8-bit) data ifc enable (0) */
93*da917039SDavid du Colombier 
94*da917039SDavid du Colombier 	/* Phyc register.  sgmii link speed is Emmc's Linkspeed. */
95*da917039SDavid du Colombier 	Rgmiills = 3<<2,	/* field */
96*da917039SDavid du Colombier 	Rls1000	= 2<<2,		/* Gb */
97*da917039SDavid du Colombier 	Rls100	= 1<<2,		/* 100Mb */
98*da917039SDavid du Colombier 	Rls10	= 0<<2,		/* 10Mb */
99*da917039SDavid du Colombier 	Rgmiihd	= 1<<1,		/* half-duplex */
100*da917039SDavid du Colombier 	Rgmiilink = 1<<0,	/* rgmii link (is up) */
101*da917039SDavid du Colombier 
102*da917039SDavid du Colombier 	/* Mc register */
103*da917039SDavid du Colombier 	Mdioen	= 1<<6,		/* mdio (mii mgmt) enable */
104*da917039SDavid du Colombier 
105*da917039SDavid du Colombier 	/* Maw1 register */
106*da917039SDavid du Colombier 	Rnw	= 1<<23,	/* multicast addr table reg read (vs write) */
107*da917039SDavid du Colombier 	Addr	= 3<<16,	/* field */
108*da917039SDavid du Colombier 
109*da917039SDavid du Colombier 	/* Afm register */
110*da917039SDavid du Colombier 	Pm	= 1<<31,	/* promiscuous mode */
111*da917039SDavid du Colombier 
112*da917039SDavid du Colombier 	/* Tis, Tie register (*rst->*en) */
113*da917039SDavid du Colombier 	Fabrrst	= 1<<0,		/* fabric read intr sts (read done) */
114*da917039SDavid du Colombier 	Miimrst	= 1<<1,		/* mii mgmt read intr sts (read done) */
115*da917039SDavid du Colombier 	Miimwst	= 1<<2,		/* mii mgmt write intr sts (write done) */
116*da917039SDavid du Colombier 	Afrst	= 1<<3,		/* addr filter read intr sts (read done) */
117*da917039SDavid du Colombier 	Afwst	= 1<<4,		/* addr filter write intr sts (write done) */
118*da917039SDavid du Colombier 	Cfgrst	= 1<<5,		/* config read intr sts (read done) */
119*da917039SDavid du Colombier 	Cfgwst	= 1<<6,		/* config write intr sts (write done) */
120*da917039SDavid du Colombier };
121*da917039SDavid du Colombier 
122*da917039SDavid du Colombier enum {
123*da917039SDavid du Colombier 	/* tunable parameters */
124*da917039SDavid du Colombier 	Defmbps	= 1000,		/* default Mb/s */
125*da917039SDavid du Colombier 	Defls	= Ls1000,	/* must match Defmbps */
126*da917039SDavid du Colombier };
127*da917039SDavid du Colombier 
128*da917039SDavid du Colombier typedef struct Temacsw Temacsw;
129*da917039SDavid du Colombier typedef struct Temacregs Temacregs;
130*da917039SDavid du Colombier struct Temacregs {
131*da917039SDavid du Colombier 	ulong	raf;		/* reset & addr filter */
132*da917039SDavid du Colombier 	ulong	tpf;		/* tx pause frame */
133*da917039SDavid du Colombier 	ulong	ifgp;		/* tx inter-frame gap adjustment */
134*da917039SDavid du Colombier 	ulong	is;		/* intr status */
135*da917039SDavid du Colombier 	ulong	ip;		/* intr pending */
136*da917039SDavid du Colombier 	ulong	ie;		/* intr enable */
137*da917039SDavid du Colombier 	ulong	pad[2];
138*da917039SDavid du Colombier 
139*da917039SDavid du Colombier 	ulong	msw;		/* msw data; shared by ifcs */
140*da917039SDavid du Colombier 	ulong	lsw;		/* lsw data; shared */
141*da917039SDavid du Colombier 	ulong	ctl;		/* control; shared */
142*da917039SDavid du Colombier 	ulong	rdy;		/* ready status */
143*da917039SDavid du Colombier 	ulong	pad2[4];
144*da917039SDavid du Colombier };
145*da917039SDavid du Colombier struct Temacsw {
146*da917039SDavid du Colombier 	Temacregs *regs;
147*da917039SDavid du Colombier };
148*da917039SDavid du Colombier 
149*da917039SDavid du Colombier extern uchar mymac[Eaddrlen];
150*da917039SDavid du Colombier 
151*da917039SDavid du Colombier static Ether *ethers[1];	/* only first ether is connected to a fifo */
152*da917039SDavid du Colombier static Lock shreglck;		/* protects shared registers */
153*da917039SDavid du Colombier 
154*da917039SDavid du Colombier static void	transmit(Ether *ether);
155*da917039SDavid du Colombier 
156*da917039SDavid du Colombier static void
getready(Temacregs * trp)157*da917039SDavid du Colombier getready(Temacregs *trp)
158*da917039SDavid du Colombier {
159*da917039SDavid du Colombier 	while ((trp->rdy & Hardacsrdy) == 0)
160*da917039SDavid du Colombier 		;
161*da917039SDavid du Colombier }
162*da917039SDavid du Colombier 
163*da917039SDavid du Colombier static ulong
rdindir(Temacregs * trp,unsigned code)164*da917039SDavid du Colombier rdindir(Temacregs *trp, unsigned code)
165*da917039SDavid du Colombier {
166*da917039SDavid du Colombier 	ulong val;
167*da917039SDavid du Colombier 
168*da917039SDavid du Colombier 	ilock(&shreglck);
169*da917039SDavid du Colombier 	getready(trp);
170*da917039SDavid du Colombier 	trp->ctl = code;
171*da917039SDavid du Colombier 	coherence();
172*da917039SDavid du Colombier 
173*da917039SDavid du Colombier 	getready(trp);
174*da917039SDavid du Colombier 	val = trp->lsw;
175*da917039SDavid du Colombier 	iunlock(&shreglck);
176*da917039SDavid du Colombier 	return val;
177*da917039SDavid du Colombier }
178*da917039SDavid du Colombier 
179*da917039SDavid du Colombier static int
wrindir(Temacregs * trp,unsigned code,ulong val)180*da917039SDavid du Colombier wrindir(Temacregs *trp, unsigned code, ulong val)
181*da917039SDavid du Colombier {
182*da917039SDavid du Colombier 	ilock(&shreglck);
183*da917039SDavid du Colombier 	getready(trp);
184*da917039SDavid du Colombier 	trp->lsw = val;
185*da917039SDavid du Colombier 	coherence();
186*da917039SDavid du Colombier 	trp->ctl = Wen | code;
187*da917039SDavid du Colombier 	coherence();
188*da917039SDavid du Colombier 
189*da917039SDavid du Colombier 	getready(trp);
190*da917039SDavid du Colombier 	iunlock(&shreglck);
191*da917039SDavid du Colombier 	return 0;
192*da917039SDavid du Colombier }
193*da917039SDavid du Colombier 
194*da917039SDavid du Colombier static int
interrupt(ulong bit)195*da917039SDavid du Colombier interrupt(ulong bit)
196*da917039SDavid du Colombier {
197*da917039SDavid du Colombier 	int e, r, sts;
198*da917039SDavid du Colombier 	Ether *ether;
199*da917039SDavid du Colombier 	Temacsw *ctlr;
200*da917039SDavid du Colombier 
201*da917039SDavid du Colombier 	r = 0;
202*da917039SDavid du Colombier 	for (e = 0; e < MaxEther; e++) {
203*da917039SDavid du Colombier 		ether = ethers[e];
204*da917039SDavid du Colombier 		if (ether == nil)
205*da917039SDavid du Colombier 			continue;
206*da917039SDavid du Colombier 		ctlr = ether->ctlr;
207*da917039SDavid du Colombier 		sts = ctlr->regs->is;
208*da917039SDavid du Colombier 		if (sts)
209*da917039SDavid du Colombier 			r = 1;
210*da917039SDavid du Colombier 		ctlr->regs->is = sts;	/* extinguish intr source */
211*da917039SDavid du Colombier 		coherence();
212*da917039SDavid du Colombier 		sts &= ~(Rxcmplt | Txcmplt | Rxdcmlock | Mgtrdy);
213*da917039SDavid du Colombier 		if (sts)
214*da917039SDavid du Colombier 			iprint("ethertemac: sts %#ux\n", sts);
215*da917039SDavid du Colombier 	}
216*da917039SDavid du Colombier 	if (r)
217*da917039SDavid du Colombier 		intrack(bit);
218*da917039SDavid du Colombier 	return r;
219*da917039SDavid du Colombier }
220*da917039SDavid du Colombier 
221*da917039SDavid du Colombier static void
reset(Ether * ether)222*da917039SDavid du Colombier reset(Ether *ether)
223*da917039SDavid du Colombier {
224*da917039SDavid du Colombier 	Temacsw *ctlr;
225*da917039SDavid du Colombier 	Temacregs *trp;
226*da917039SDavid du Colombier 
227*da917039SDavid du Colombier 	ctlr = ether->ctlr;
228*da917039SDavid du Colombier 	trp = ctlr->regs;
229*da917039SDavid du Colombier 	trp->ie = 0;
230*da917039SDavid du Colombier 	coherence();
231*da917039SDavid du Colombier 	/* don't use raf to reset: that resets both interfaces */
232*da917039SDavid du Colombier 	wrindir(trp, Tc,   Rst);
233*da917039SDavid du Colombier 	while (rdindir(trp, Tc) & Rst)
234*da917039SDavid du Colombier 		;
235*da917039SDavid du Colombier 	wrindir(trp, Rcw1, Rst);
236*da917039SDavid du Colombier 	while (rdindir(trp, Rcw1) & Rst)
237*da917039SDavid du Colombier 		;
238*da917039SDavid du Colombier 	llfiforeset();
239*da917039SDavid du Colombier }
240*da917039SDavid du Colombier 
241*da917039SDavid du Colombier static void
attach(Ether *)242*da917039SDavid du Colombier attach(Ether *)
243*da917039SDavid du Colombier {
244*da917039SDavid du Colombier }
245*da917039SDavid du Colombier 
246*da917039SDavid du Colombier static void
transmit(Ether * ether)247*da917039SDavid du Colombier transmit(Ether *ether)
248*da917039SDavid du Colombier {
249*da917039SDavid du Colombier 	RingBuf *tb;
250*da917039SDavid du Colombier 
251*da917039SDavid du Colombier 	if (ether->tbusy)
252*da917039SDavid du Colombier 		return;
253*da917039SDavid du Colombier 	tb = &ether->tb[ether->ti];
254*da917039SDavid du Colombier 	if (tb->owner != Interface)
255*da917039SDavid du Colombier 		return;
256*da917039SDavid du Colombier 	llfifotransmit(tb->pkt, tb->len);
257*da917039SDavid du Colombier 	coherence();
258*da917039SDavid du Colombier 	tb->owner = Host;
259*da917039SDavid du Colombier 	coherence();
260*da917039SDavid du Colombier 	ether->ti = NEXT(ether->ti, ether->ntb);
261*da917039SDavid du Colombier 	coherence();
262*da917039SDavid du Colombier }
263*da917039SDavid du Colombier 
264*da917039SDavid du Colombier static void
detach(Ether * ether)265*da917039SDavid du Colombier detach(Ether *ether)
266*da917039SDavid du Colombier {
267*da917039SDavid du Colombier 	reset(ether);
268*da917039SDavid du Colombier }
269*da917039SDavid du Colombier 
270*da917039SDavid du Colombier int
temacreset(Ether * ether)271*da917039SDavid du Colombier temacreset(Ether* ether)
272*da917039SDavid du Colombier {
273*da917039SDavid du Colombier 	int i;
274*da917039SDavid du Colombier 	ulong ealo, eahi;
275*da917039SDavid du Colombier 	uvlong ea;
276*da917039SDavid du Colombier 	Temacsw *ctlr;
277*da917039SDavid du Colombier 	Temacregs *trp;
278*da917039SDavid du Colombier 
279*da917039SDavid du Colombier 	if ((unsigned)ether->ctlrno >= nelem(ethers) || ethers[ether->ctlrno])
280*da917039SDavid du Colombier 		return -1;		/* already probed & found */
281*da917039SDavid du Colombier 	trp = (Temacregs *)Temac + ether->ctlrno;
282*da917039SDavid du Colombier 	if (probeaddr((uintptr)trp) < 0)
283*da917039SDavid du Colombier 		return -1;
284*da917039SDavid du Colombier 
285*da917039SDavid du Colombier 	ethers[ether->ctlrno] = ether;
286*da917039SDavid du Colombier 	ether->ctlr = ctlr = malloc(sizeof *ctlr);
287*da917039SDavid du Colombier 	ctlr->regs = trp;
288*da917039SDavid du Colombier 
289*da917039SDavid du Colombier 	/*
290*da917039SDavid du Colombier 	 * Determine media.
291*da917039SDavid du Colombier 	 */
292*da917039SDavid du Colombier 	ether->mbps = Defmbps;
293*da917039SDavid du Colombier //	ether->mbps = media(ether, 1);
294*da917039SDavid du Colombier 
295*da917039SDavid du Colombier 	/*
296*da917039SDavid du Colombier 	 * Initialise descriptor rings, ethernet address.
297*da917039SDavid du Colombier 	 */
298*da917039SDavid du Colombier 	ether->nrb = Nrde;
299*da917039SDavid du Colombier 	ether->ntb = Ntde;
300*da917039SDavid du Colombier 	ether->rb = malloc(Nrde * sizeof(RingBuf));
301*da917039SDavid du Colombier 	ether->tb = malloc(Ntde * sizeof(RingBuf));
302*da917039SDavid du Colombier 	ether->port = Temac;
303*da917039SDavid du Colombier 
304*da917039SDavid du Colombier 	reset(ether);
305*da917039SDavid du Colombier 	delay(1);
306*da917039SDavid du Colombier 
307*da917039SDavid du Colombier 	llfifoinit(ether);
308*da917039SDavid du Colombier 
309*da917039SDavid du Colombier 	wrindir(trp, Mc, Mdioen | 29);	/* 29 is divisor; see p.47 of ds537 */
310*da917039SDavid du Colombier 	delay(100);			/* guess */
311*da917039SDavid du Colombier 
312*da917039SDavid du Colombier 	/*
313*da917039SDavid du Colombier 	 * mac addr is stored little-endian in longs in Uaw[01].
314*da917039SDavid du Colombier 	 * default address is rubbish.
315*da917039SDavid du Colombier 	 */
316*da917039SDavid du Colombier 	memmove(ether->ea, mymac, Eaddrlen);
317*da917039SDavid du Colombier 	ea = 0;
318*da917039SDavid du Colombier 	for (i = 0; i < Eaddrlen; i++)
319*da917039SDavid du Colombier 		ea |= (uvlong)mymac[i] << (i * 8);
320*da917039SDavid du Colombier 	wrindir(trp, Uaw0, (ulong)ea);
321*da917039SDavid du Colombier 	wrindir(trp, Uaw1, (ulong)(ea >> 32));
322*da917039SDavid du Colombier 	ealo = rdindir(trp, Uaw0);
323*da917039SDavid du Colombier 	eahi = rdindir(trp, Uaw1) & 0xffff;
324*da917039SDavid du Colombier 	if (ealo != (ulong)ea || eahi != (ulong)(ea >> 32))
325*da917039SDavid du Colombier 		panic("temac mac address wouldn't set, got %lux %lux",
326*da917039SDavid du Colombier 			eahi, ealo);
327*da917039SDavid du Colombier 
328*da917039SDavid du Colombier 	/*
329*da917039SDavid du Colombier 	 * admit broadcast packets too
330*da917039SDavid du Colombier 	 */
331*da917039SDavid du Colombier 	wrindir(trp, Maw0, ~0ul);
332*da917039SDavid du Colombier 	wrindir(trp, Maw1, 0xffff);	/* write to mat reg 0 */
333*da917039SDavid du Colombier 
334*da917039SDavid du Colombier 	wrindir(trp, Afm, 0);		/* not promiscuous */
335*da917039SDavid du Colombier 	wrindir(trp, Tc, Tx);
336*da917039SDavid du Colombier 	wrindir(trp, Emmc, Defls);
337*da917039SDavid du Colombier 
338*da917039SDavid du Colombier /*	intrenable(Inttemac, interrupt); /* done by ether.c */
339*da917039SDavid du Colombier 	trp->ie = Rxrject | Rxfifoovr;	/* just errors */
340*da917039SDavid du Colombier 	coherence();
341*da917039SDavid du Colombier 
342*da917039SDavid du Colombier 	wrindir(trp, Tc,   Tx);
343*da917039SDavid du Colombier 	wrindir(trp, Rcw1, Rx);
344*da917039SDavid du Colombier 
345*da917039SDavid du Colombier 	/*
346*da917039SDavid du Colombier 	 * Linkage to the generic ethernet driver.
347*da917039SDavid du Colombier 	 */
348*da917039SDavid du Colombier 	ether->attach = attach;
349*da917039SDavid du Colombier 	ether->transmit = transmit;
350*da917039SDavid du Colombier 	ether->interrupt = interrupt;
351*da917039SDavid du Colombier 	ether->detach = detach;
352*da917039SDavid du Colombier 
353*da917039SDavid du Colombier 	return 0;
354*da917039SDavid du Colombier }
355