xref: /inferno-os/os/boot/pc/ether8390.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth /*
2*74a4d8c2SCharles.Forsyth  * National Semiconductor DP8390 and clone
3*74a4d8c2SCharles.Forsyth  * Network Interface Controller.
4*74a4d8c2SCharles.Forsyth  */
5*74a4d8c2SCharles.Forsyth #include "u.h"
6*74a4d8c2SCharles.Forsyth #include "lib.h"
7*74a4d8c2SCharles.Forsyth #include "mem.h"
8*74a4d8c2SCharles.Forsyth #include "dat.h"
9*74a4d8c2SCharles.Forsyth #include "fns.h"
10*74a4d8c2SCharles.Forsyth #include "io.h"
11*74a4d8c2SCharles.Forsyth 
12*74a4d8c2SCharles.Forsyth #include "etherif.h"
13*74a4d8c2SCharles.Forsyth #include "ether8390.h"
14*74a4d8c2SCharles.Forsyth 
15*74a4d8c2SCharles.Forsyth enum {					/* NIC core registers */
16*74a4d8c2SCharles.Forsyth 	Cr		= 0x00,		/* command register, all pages */
17*74a4d8c2SCharles.Forsyth 
18*74a4d8c2SCharles.Forsyth 					/* Page 0, read */
19*74a4d8c2SCharles.Forsyth 	Clda0		= 0x01,		/* current local DMA address 0 */
20*74a4d8c2SCharles.Forsyth 	Clda1		= 0x02,		/* current local DMA address 1 */
21*74a4d8c2SCharles.Forsyth 	Bnry		= 0x03,		/* boundary pointer (R/W) */
22*74a4d8c2SCharles.Forsyth 	Tsr		= 0x04,		/* transmit status register */
23*74a4d8c2SCharles.Forsyth 	Ncr		= 0x05,		/* number of collisions register */
24*74a4d8c2SCharles.Forsyth 	Fifo		= 0x06,		/* FIFO */
25*74a4d8c2SCharles.Forsyth 	Isr		= 0x07,		/* interrupt status register (R/W) */
26*74a4d8c2SCharles.Forsyth 	Crda0		= 0x08,		/* current remote DMA address 0 */
27*74a4d8c2SCharles.Forsyth 	Crda1		= 0x09,		/* current remote DMA address 1 */
28*74a4d8c2SCharles.Forsyth 	Rsr		= 0x0C,		/* receive status register */
29*74a4d8c2SCharles.Forsyth 	Cntr0		= 0x0D,		/* frame alignment errors */
30*74a4d8c2SCharles.Forsyth 	Cntr1		= 0x0E,		/* CRC errors */
31*74a4d8c2SCharles.Forsyth 	Cntr2		= 0x0F,		/* missed packet errors */
32*74a4d8c2SCharles.Forsyth 
33*74a4d8c2SCharles.Forsyth 					/* Page 0, write */
34*74a4d8c2SCharles.Forsyth 	Pstart		= 0x01,		/* page start register */
35*74a4d8c2SCharles.Forsyth 	Pstop		= 0x02,		/* page stop register */
36*74a4d8c2SCharles.Forsyth 	Tpsr		= 0x04,		/* transmit page start address */
37*74a4d8c2SCharles.Forsyth 	Tbcr0		= 0x05,		/* transmit byte count register 0 */
38*74a4d8c2SCharles.Forsyth 	Tbcr1		= 0x06,		/* transmit byte count register 1 */
39*74a4d8c2SCharles.Forsyth 	Rsar0		= 0x08,		/* remote start address register 0 */
40*74a4d8c2SCharles.Forsyth 	Rsar1		= 0x09,		/* remote start address register 1 */
41*74a4d8c2SCharles.Forsyth 	Rbcr0		= 0x0A,		/* remote byte count register 0 */
42*74a4d8c2SCharles.Forsyth 	Rbcr1		= 0x0B,		/* remote byte count register 1 */
43*74a4d8c2SCharles.Forsyth 	Rcr		= 0x0C,		/* receive configuration register */
44*74a4d8c2SCharles.Forsyth 	Tcr		= 0x0D,		/* transmit configuration register */
45*74a4d8c2SCharles.Forsyth 	Dcr		= 0x0E,		/* data configuration register */
46*74a4d8c2SCharles.Forsyth 	Imr		= 0x0F,		/* interrupt mask */
47*74a4d8c2SCharles.Forsyth 
48*74a4d8c2SCharles.Forsyth 					/* Page 1, read/write */
49*74a4d8c2SCharles.Forsyth 	Par0		= 0x01,		/* physical address register 0 */
50*74a4d8c2SCharles.Forsyth 	Curr		= 0x07,		/* current page register */
51*74a4d8c2SCharles.Forsyth 	Mar0		= 0x08,		/* multicast address register 0 */
52*74a4d8c2SCharles.Forsyth };
53*74a4d8c2SCharles.Forsyth 
54*74a4d8c2SCharles.Forsyth enum {					/* Cr */
55*74a4d8c2SCharles.Forsyth 	Stp		= 0x01,		/* stop */
56*74a4d8c2SCharles.Forsyth 	Sta		= 0x02,		/* start */
57*74a4d8c2SCharles.Forsyth 	Txp		= 0x04,		/* transmit packet */
58*74a4d8c2SCharles.Forsyth 	Rd0		= 0x08,		/* remote DMA command */
59*74a4d8c2SCharles.Forsyth 	Rd1		= 0x10,
60*74a4d8c2SCharles.Forsyth 	Rd2		= 0x20,
61*74a4d8c2SCharles.Forsyth 	RdREAD		= Rd0,		/* remote read */
62*74a4d8c2SCharles.Forsyth 	RdWRITE		= Rd1,		/* remote write */
63*74a4d8c2SCharles.Forsyth 	RdSEND		= Rd1|Rd0,	/* send packet */
64*74a4d8c2SCharles.Forsyth 	RdABORT		= Rd2,		/* abort/complete remote DMA */
65*74a4d8c2SCharles.Forsyth 	Ps0		= 0x40,		/* page select */
66*74a4d8c2SCharles.Forsyth 	Ps1		= 0x80,
67*74a4d8c2SCharles.Forsyth 	Page0		= 0x00,
68*74a4d8c2SCharles.Forsyth 	Page1		= Ps0,
69*74a4d8c2SCharles.Forsyth 	Page2		= Ps1,
70*74a4d8c2SCharles.Forsyth };
71*74a4d8c2SCharles.Forsyth 
72*74a4d8c2SCharles.Forsyth enum {					/* Isr/Imr */
73*74a4d8c2SCharles.Forsyth 	Prx		= 0x01,		/* packet received */
74*74a4d8c2SCharles.Forsyth 	Ptx		= 0x02,		/* packet transmitted */
75*74a4d8c2SCharles.Forsyth 	Rxe		= 0x04,		/* receive error */
76*74a4d8c2SCharles.Forsyth 	Txe		= 0x08,		/* transmit error */
77*74a4d8c2SCharles.Forsyth 	Ovw		= 0x10,		/* overwrite warning */
78*74a4d8c2SCharles.Forsyth 	Cnt		= 0x20,		/* counter overflow */
79*74a4d8c2SCharles.Forsyth 	Rdc		= 0x40,		/* remote DMA complete */
80*74a4d8c2SCharles.Forsyth 	Rst		= 0x80,		/* reset status */
81*74a4d8c2SCharles.Forsyth };
82*74a4d8c2SCharles.Forsyth 
83*74a4d8c2SCharles.Forsyth enum {					/* Dcr */
84*74a4d8c2SCharles.Forsyth 	Wts		= 0x01,		/* word transfer select */
85*74a4d8c2SCharles.Forsyth 	Bos		= 0x02,		/* byte order select */
86*74a4d8c2SCharles.Forsyth 	Las		= 0x04,		/* long address select */
87*74a4d8c2SCharles.Forsyth 	Ls		= 0x08,		/* loopback select */
88*74a4d8c2SCharles.Forsyth 	Arm		= 0x10,		/* auto-initialise remote */
89*74a4d8c2SCharles.Forsyth 	Ft0		= 0x20,		/* FIFO threshold select */
90*74a4d8c2SCharles.Forsyth 	Ft1		= 0x40,
91*74a4d8c2SCharles.Forsyth 	Ft1WORD		= 0x00,
92*74a4d8c2SCharles.Forsyth 	Ft2WORD		= Ft0,
93*74a4d8c2SCharles.Forsyth 	Ft4WORD		= Ft1,
94*74a4d8c2SCharles.Forsyth 	Ft6WORD		= Ft1|Ft0,
95*74a4d8c2SCharles.Forsyth };
96*74a4d8c2SCharles.Forsyth 
97*74a4d8c2SCharles.Forsyth enum {					/* Tcr */
98*74a4d8c2SCharles.Forsyth 	Crc		= 0x01,		/* inhibit CRC */
99*74a4d8c2SCharles.Forsyth 	Lb0		= 0x02,		/* encoded loopback control */
100*74a4d8c2SCharles.Forsyth 	Lb1		= 0x04,
101*74a4d8c2SCharles.Forsyth 	LpbkNORMAL	= 0x00,		/* normal operation */
102*74a4d8c2SCharles.Forsyth 	LpbkNIC		= Lb0,		/* internal NIC module loopback */
103*74a4d8c2SCharles.Forsyth 	LpbkENDEC	= Lb1,		/* internal ENDEC module loopback */
104*74a4d8c2SCharles.Forsyth 	LpbkEXTERNAL	= Lb1|Lb0,	/* external loopback */
105*74a4d8c2SCharles.Forsyth 	Atd		= 0x08,		/* auto transmit disable */
106*74a4d8c2SCharles.Forsyth 	Ofst		= 0x10,		/* collision offset enable */
107*74a4d8c2SCharles.Forsyth };
108*74a4d8c2SCharles.Forsyth 
109*74a4d8c2SCharles.Forsyth enum {					/* Tsr */
110*74a4d8c2SCharles.Forsyth 	Ptxok		= 0x01,		/* packet transmitted */
111*74a4d8c2SCharles.Forsyth 	Col		= 0x04,		/* transmit collided */
112*74a4d8c2SCharles.Forsyth 	Abt		= 0x08,		/* tranmit aborted */
113*74a4d8c2SCharles.Forsyth 	Crs		= 0x10,		/* carrier sense lost */
114*74a4d8c2SCharles.Forsyth 	Fu		= 0x20,		/* FIFO underrun */
115*74a4d8c2SCharles.Forsyth 	Cdh		= 0x40,		/* CD heartbeat */
116*74a4d8c2SCharles.Forsyth 	Owc		= 0x80,		/* out of window collision */
117*74a4d8c2SCharles.Forsyth };
118*74a4d8c2SCharles.Forsyth 
119*74a4d8c2SCharles.Forsyth enum {					/* Rcr */
120*74a4d8c2SCharles.Forsyth 	Sep		= 0x01,		/* save errored packets */
121*74a4d8c2SCharles.Forsyth 	Ar		= 0x02,		/* accept runt packets */
122*74a4d8c2SCharles.Forsyth 	Ab		= 0x04,		/* accept broadcast */
123*74a4d8c2SCharles.Forsyth 	Am		= 0x08,		/* accept multicast */
124*74a4d8c2SCharles.Forsyth 	Pro		= 0x10,		/* promiscuous physical */
125*74a4d8c2SCharles.Forsyth 	Mon		= 0x20,		/* monitor mode */
126*74a4d8c2SCharles.Forsyth };
127*74a4d8c2SCharles.Forsyth 
128*74a4d8c2SCharles.Forsyth enum {					/* Rsr */
129*74a4d8c2SCharles.Forsyth 	Prxok		= 0x01,		/* packet received intact */
130*74a4d8c2SCharles.Forsyth 	Crce		= 0x02,		/* CRC error */
131*74a4d8c2SCharles.Forsyth 	Fae		= 0x04,		/* frame alignment error */
132*74a4d8c2SCharles.Forsyth 	Fo		= 0x08,		/* FIFO overrun */
133*74a4d8c2SCharles.Forsyth 	Mpa		= 0x10,		/* missed packet */
134*74a4d8c2SCharles.Forsyth 	Phy		= 0x20,		/* physical/multicast address */
135*74a4d8c2SCharles.Forsyth 	Dis		= 0x40,		/* receiver disabled */
136*74a4d8c2SCharles.Forsyth 	Dfr		= 0x80,		/* deferring */
137*74a4d8c2SCharles.Forsyth };
138*74a4d8c2SCharles.Forsyth 
139*74a4d8c2SCharles.Forsyth typedef struct {
140*74a4d8c2SCharles.Forsyth 	uchar	status;
141*74a4d8c2SCharles.Forsyth 	uchar	next;
142*74a4d8c2SCharles.Forsyth 	uchar	len0;
143*74a4d8c2SCharles.Forsyth 	uchar	len1;
144*74a4d8c2SCharles.Forsyth } Hdr;
145*74a4d8c2SCharles.Forsyth 
146*74a4d8c2SCharles.Forsyth void
dp8390getea(Ether * ether,uchar * ea)147*74a4d8c2SCharles.Forsyth dp8390getea(Ether* ether, uchar* ea)
148*74a4d8c2SCharles.Forsyth {
149*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
150*74a4d8c2SCharles.Forsyth 	uchar cr;
151*74a4d8c2SCharles.Forsyth 	int i;
152*74a4d8c2SCharles.Forsyth 
153*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
154*74a4d8c2SCharles.Forsyth 
155*74a4d8c2SCharles.Forsyth 	/*
156*74a4d8c2SCharles.Forsyth 	 * Get the ethernet address from the chip.
157*74a4d8c2SCharles.Forsyth 	 * Take care to restore the command register
158*74a4d8c2SCharles.Forsyth 	 * afterwards.
159*74a4d8c2SCharles.Forsyth 	 */
160*74a4d8c2SCharles.Forsyth 	ilock(ctlr);
161*74a4d8c2SCharles.Forsyth 	cr = regr(ctlr, Cr) & ~Txp;
162*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
163*74a4d8c2SCharles.Forsyth 	for(i = 0; i < Eaddrlen; i++)
164*74a4d8c2SCharles.Forsyth 		ea[i] = regr(ctlr, Par0+i);
165*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, cr);
166*74a4d8c2SCharles.Forsyth 	iunlock(ctlr);
167*74a4d8c2SCharles.Forsyth }
168*74a4d8c2SCharles.Forsyth 
169*74a4d8c2SCharles.Forsyth void
dp8390setea(Ether * ether)170*74a4d8c2SCharles.Forsyth dp8390setea(Ether* ether)
171*74a4d8c2SCharles.Forsyth {
172*74a4d8c2SCharles.Forsyth 	int i;
173*74a4d8c2SCharles.Forsyth 	uchar cr;
174*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
175*74a4d8c2SCharles.Forsyth 
176*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
177*74a4d8c2SCharles.Forsyth 
178*74a4d8c2SCharles.Forsyth 	/*
179*74a4d8c2SCharles.Forsyth 	 * Set the ethernet address into the chip.
180*74a4d8c2SCharles.Forsyth 	 * Take care to restore the command register
181*74a4d8c2SCharles.Forsyth 	 * afterwards. Don't care about multicast
182*74a4d8c2SCharles.Forsyth 	 * addresses as multicast is never enabled
183*74a4d8c2SCharles.Forsyth 	 * (currently).
184*74a4d8c2SCharles.Forsyth 	 */
185*74a4d8c2SCharles.Forsyth 	ilock(ctlr);
186*74a4d8c2SCharles.Forsyth 	cr = regr(ctlr, Cr) & ~Txp;
187*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
188*74a4d8c2SCharles.Forsyth 	for(i = 0; i < Eaddrlen; i++)
189*74a4d8c2SCharles.Forsyth 		regw(ctlr, Par0+i, ether->ea[i]);
190*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, cr);
191*74a4d8c2SCharles.Forsyth 	iunlock(ctlr);
192*74a4d8c2SCharles.Forsyth }
193*74a4d8c2SCharles.Forsyth 
194*74a4d8c2SCharles.Forsyth static void*
_dp8390read(Dp8390 * ctlr,void * to,ulong from,ulong len)195*74a4d8c2SCharles.Forsyth _dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
196*74a4d8c2SCharles.Forsyth {
197*74a4d8c2SCharles.Forsyth 	uchar cr;
198*74a4d8c2SCharles.Forsyth 	int timo;
199*74a4d8c2SCharles.Forsyth 
200*74a4d8c2SCharles.Forsyth 	/*
201*74a4d8c2SCharles.Forsyth 	 * Read some data at offset 'from' in the card's memory
202*74a4d8c2SCharles.Forsyth 	 * using the DP8390 remote DMA facility, and place it at
203*74a4d8c2SCharles.Forsyth 	 * 'to' in main memory, via the I/O data port.
204*74a4d8c2SCharles.Forsyth 	 */
205*74a4d8c2SCharles.Forsyth 	cr = regr(ctlr, Cr) & ~Txp;
206*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdABORT|Sta);
207*74a4d8c2SCharles.Forsyth 	regw(ctlr, Isr, Rdc);
208*74a4d8c2SCharles.Forsyth 
209*74a4d8c2SCharles.Forsyth 	/*
210*74a4d8c2SCharles.Forsyth 	 * Set up the remote DMA address and count.
211*74a4d8c2SCharles.Forsyth 	 */
212*74a4d8c2SCharles.Forsyth 	len = ROUNDUP(len, ctlr->width);
213*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rbcr0, len & 0xFF);
214*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rbcr1, (len>>8) & 0xFF);
215*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rsar0, from & 0xFF);
216*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rsar1, (from>>8) & 0xFF);
217*74a4d8c2SCharles.Forsyth 
218*74a4d8c2SCharles.Forsyth 	/*
219*74a4d8c2SCharles.Forsyth 	 * Start the remote DMA read and suck the data
220*74a4d8c2SCharles.Forsyth 	 * out of the I/O port.
221*74a4d8c2SCharles.Forsyth 	 */
222*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdREAD|Sta);
223*74a4d8c2SCharles.Forsyth 	rdread(ctlr, to, len);
224*74a4d8c2SCharles.Forsyth 
225*74a4d8c2SCharles.Forsyth 	/*
226*74a4d8c2SCharles.Forsyth 	 * Wait for the remote DMA to complete. The timeout
227*74a4d8c2SCharles.Forsyth 	 * is necessary because this routine may be called on
228*74a4d8c2SCharles.Forsyth 	 * a non-existent chip during initialisation and, due
229*74a4d8c2SCharles.Forsyth 	 * to the miracles of the bus, it's possible to get this
230*74a4d8c2SCharles.Forsyth 	 * far and still be talking to a slot full of nothing.
231*74a4d8c2SCharles.Forsyth 	 */
232*74a4d8c2SCharles.Forsyth 	for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
233*74a4d8c2SCharles.Forsyth 			;
234*74a4d8c2SCharles.Forsyth 
235*74a4d8c2SCharles.Forsyth 	regw(ctlr, Isr, Rdc);
236*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, cr);
237*74a4d8c2SCharles.Forsyth 
238*74a4d8c2SCharles.Forsyth 	return to;
239*74a4d8c2SCharles.Forsyth }
240*74a4d8c2SCharles.Forsyth 
241*74a4d8c2SCharles.Forsyth void*
dp8390read(Dp8390 * ctlr,void * to,ulong from,ulong len)242*74a4d8c2SCharles.Forsyth dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
243*74a4d8c2SCharles.Forsyth {
244*74a4d8c2SCharles.Forsyth 	void *v;
245*74a4d8c2SCharles.Forsyth 
246*74a4d8c2SCharles.Forsyth 	ilock(ctlr);
247*74a4d8c2SCharles.Forsyth 	v = _dp8390read(ctlr, to, from, len);
248*74a4d8c2SCharles.Forsyth 	iunlock(ctlr);
249*74a4d8c2SCharles.Forsyth 
250*74a4d8c2SCharles.Forsyth 	return v;
251*74a4d8c2SCharles.Forsyth }
252*74a4d8c2SCharles.Forsyth 
253*74a4d8c2SCharles.Forsyth static void*
dp8390write(Dp8390 * ctlr,ulong to,void * from,ulong len)254*74a4d8c2SCharles.Forsyth dp8390write(Dp8390* ctlr, ulong to, void* from, ulong len)
255*74a4d8c2SCharles.Forsyth {
256*74a4d8c2SCharles.Forsyth 	ulong crda;
257*74a4d8c2SCharles.Forsyth 	uchar cr;
258*74a4d8c2SCharles.Forsyth 	int timo, width;
259*74a4d8c2SCharles.Forsyth 
260*74a4d8c2SCharles.Forsyth top:
261*74a4d8c2SCharles.Forsyth 	/*
262*74a4d8c2SCharles.Forsyth 	 * Write some data to offset 'to' in the card's memory
263*74a4d8c2SCharles.Forsyth 	 * using the DP8390 remote DMA facility, reading it at
264*74a4d8c2SCharles.Forsyth 	 * 'from' in main memory, via the I/O data port.
265*74a4d8c2SCharles.Forsyth 	 */
266*74a4d8c2SCharles.Forsyth 	cr = regr(ctlr, Cr) & ~Txp;
267*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdABORT|Sta);
268*74a4d8c2SCharles.Forsyth 	regw(ctlr, Isr, Rdc);
269*74a4d8c2SCharles.Forsyth 
270*74a4d8c2SCharles.Forsyth 	len = ROUNDUP(len, ctlr->width);
271*74a4d8c2SCharles.Forsyth 
272*74a4d8c2SCharles.Forsyth 	/*
273*74a4d8c2SCharles.Forsyth 	 * Set up the remote DMA address and count.
274*74a4d8c2SCharles.Forsyth 	 * This is straight from the DP8390[12D] datasheet,
275*74a4d8c2SCharles.Forsyth 	 * hence the initial set up for read.
276*74a4d8c2SCharles.Forsyth 	 * Assumption here that the A7000 EtherV card will
277*74a4d8c2SCharles.Forsyth 	 * never need a dummyrr.
278*74a4d8c2SCharles.Forsyth 	 */
279*74a4d8c2SCharles.Forsyth 	if(ctlr->dummyrr && (ctlr->width == 1 || ctlr->width == 2)){
280*74a4d8c2SCharles.Forsyth 		if(ctlr->width == 2)
281*74a4d8c2SCharles.Forsyth 			width = 1;
282*74a4d8c2SCharles.Forsyth 		else
283*74a4d8c2SCharles.Forsyth 			width = 0;
284*74a4d8c2SCharles.Forsyth 		crda = to-1-width;
285*74a4d8c2SCharles.Forsyth 		regw(ctlr, Rbcr0, (len+1+width) & 0xFF);
286*74a4d8c2SCharles.Forsyth 		regw(ctlr, Rbcr1, ((len+1+width)>>8) & 0xFF);
287*74a4d8c2SCharles.Forsyth 		regw(ctlr, Rsar0, crda & 0xFF);
288*74a4d8c2SCharles.Forsyth 		regw(ctlr, Rsar1, (crda>>8) & 0xFF);
289*74a4d8c2SCharles.Forsyth 		regw(ctlr, Cr, Page0|RdREAD|Sta);
290*74a4d8c2SCharles.Forsyth 
291*74a4d8c2SCharles.Forsyth 		for(timo=0;; timo++){
292*74a4d8c2SCharles.Forsyth 			if(timo > 10000){
293*74a4d8c2SCharles.Forsyth 				print("ether8390: dummyrr timeout; assuming nodummyrr\n");
294*74a4d8c2SCharles.Forsyth 				ctlr->dummyrr = 0;
295*74a4d8c2SCharles.Forsyth 				goto top;
296*74a4d8c2SCharles.Forsyth 			}
297*74a4d8c2SCharles.Forsyth 			crda = regr(ctlr, Crda0);
298*74a4d8c2SCharles.Forsyth 			crda |= regr(ctlr, Crda1)<<8;
299*74a4d8c2SCharles.Forsyth 			if(crda == to){
300*74a4d8c2SCharles.Forsyth 				/*
301*74a4d8c2SCharles.Forsyth 				 * Start the remote DMA write and make sure
302*74a4d8c2SCharles.Forsyth 				 * the registers are correct.
303*74a4d8c2SCharles.Forsyth 				 */
304*74a4d8c2SCharles.Forsyth 				regw(ctlr, Cr, Page0|RdWRITE|Sta);
305*74a4d8c2SCharles.Forsyth 
306*74a4d8c2SCharles.Forsyth 				crda = regr(ctlr, Crda0);
307*74a4d8c2SCharles.Forsyth 				crda |= regr(ctlr, Crda1)<<8;
308*74a4d8c2SCharles.Forsyth 				if(crda != to)
309*74a4d8c2SCharles.Forsyth 					panic("crda write %d to %d\n", crda, to);
310*74a4d8c2SCharles.Forsyth 
311*74a4d8c2SCharles.Forsyth 				break;
312*74a4d8c2SCharles.Forsyth 			}
313*74a4d8c2SCharles.Forsyth 		}
314*74a4d8c2SCharles.Forsyth 	}
315*74a4d8c2SCharles.Forsyth 	else{
316*74a4d8c2SCharles.Forsyth 		regw(ctlr, Rsar0, to & 0xFF);
317*74a4d8c2SCharles.Forsyth 		regw(ctlr, Rsar1, (to>>8) & 0xFF);
318*74a4d8c2SCharles.Forsyth 		regw(ctlr, Rbcr0, len & 0xFF);
319*74a4d8c2SCharles.Forsyth 		regw(ctlr, Rbcr1, (len>>8) & 0xFF);
320*74a4d8c2SCharles.Forsyth 		regw(ctlr, Cr, Page0|RdWRITE|Sta);
321*74a4d8c2SCharles.Forsyth 	}
322*74a4d8c2SCharles.Forsyth 
323*74a4d8c2SCharles.Forsyth 	/*
324*74a4d8c2SCharles.Forsyth 	 * Pump the data into the I/O port
325*74a4d8c2SCharles.Forsyth 	 * then wait for the remote DMA to finish.
326*74a4d8c2SCharles.Forsyth 	 */
327*74a4d8c2SCharles.Forsyth 	rdwrite(ctlr, from, len);
328*74a4d8c2SCharles.Forsyth 	for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
329*74a4d8c2SCharles.Forsyth 			;
330*74a4d8c2SCharles.Forsyth 
331*74a4d8c2SCharles.Forsyth 	regw(ctlr, Isr, Rdc);
332*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, cr);
333*74a4d8c2SCharles.Forsyth 
334*74a4d8c2SCharles.Forsyth 	return (void*)to;
335*74a4d8c2SCharles.Forsyth }
336*74a4d8c2SCharles.Forsyth 
337*74a4d8c2SCharles.Forsyth static void
ringinit(Dp8390 * ctlr)338*74a4d8c2SCharles.Forsyth ringinit(Dp8390* ctlr)
339*74a4d8c2SCharles.Forsyth {
340*74a4d8c2SCharles.Forsyth 	regw(ctlr, Pstart, ctlr->pstart);
341*74a4d8c2SCharles.Forsyth 	regw(ctlr, Pstop, ctlr->pstop);
342*74a4d8c2SCharles.Forsyth 	regw(ctlr, Bnry, ctlr->pstop-1);
343*74a4d8c2SCharles.Forsyth 
344*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page1|RdABORT|Stp);
345*74a4d8c2SCharles.Forsyth 	regw(ctlr, Curr, ctlr->pstart);
346*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdABORT|Stp);
347*74a4d8c2SCharles.Forsyth 
348*74a4d8c2SCharles.Forsyth 	ctlr->nxtpkt = ctlr->pstart;
349*74a4d8c2SCharles.Forsyth }
350*74a4d8c2SCharles.Forsyth 
351*74a4d8c2SCharles.Forsyth static uchar
getcurr(Dp8390 * ctlr)352*74a4d8c2SCharles.Forsyth getcurr(Dp8390* ctlr)
353*74a4d8c2SCharles.Forsyth {
354*74a4d8c2SCharles.Forsyth 	uchar cr, curr;
355*74a4d8c2SCharles.Forsyth 
356*74a4d8c2SCharles.Forsyth 	cr = regr(ctlr, Cr) & ~Txp;
357*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
358*74a4d8c2SCharles.Forsyth 	curr = regr(ctlr, Curr);
359*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, cr);
360*74a4d8c2SCharles.Forsyth 
361*74a4d8c2SCharles.Forsyth 	return curr;
362*74a4d8c2SCharles.Forsyth }
363*74a4d8c2SCharles.Forsyth 
364*74a4d8c2SCharles.Forsyth static void
receive(Ether * ether)365*74a4d8c2SCharles.Forsyth receive(Ether* ether)
366*74a4d8c2SCharles.Forsyth {
367*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
368*74a4d8c2SCharles.Forsyth 	uchar curr, *p;
369*74a4d8c2SCharles.Forsyth 	Hdr hdr;
370*74a4d8c2SCharles.Forsyth 	ulong count, data, len;
371*74a4d8c2SCharles.Forsyth 	RingBuf *ring;
372*74a4d8c2SCharles.Forsyth 
373*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
374*74a4d8c2SCharles.Forsyth 	for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){
375*74a4d8c2SCharles.Forsyth 		data = ctlr->nxtpkt*Dp8390BufSz;
376*74a4d8c2SCharles.Forsyth 		if(ctlr->ram)
377*74a4d8c2SCharles.Forsyth 			memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr));
378*74a4d8c2SCharles.Forsyth 		else
379*74a4d8c2SCharles.Forsyth 			_dp8390read(ctlr, &hdr, data, sizeof(Hdr));
380*74a4d8c2SCharles.Forsyth 
381*74a4d8c2SCharles.Forsyth 		/*
382*74a4d8c2SCharles.Forsyth 		 * Don't believe the upper byte count, work it
383*74a4d8c2SCharles.Forsyth 		 * out from the software next-page pointer and
384*74a4d8c2SCharles.Forsyth 		 * the current next-page pointer.
385*74a4d8c2SCharles.Forsyth 		 */
386*74a4d8c2SCharles.Forsyth 		if(hdr.next > ctlr->nxtpkt)
387*74a4d8c2SCharles.Forsyth 			len = hdr.next - ctlr->nxtpkt - 1;
388*74a4d8c2SCharles.Forsyth 		else
389*74a4d8c2SCharles.Forsyth 			len = (ctlr->pstop-ctlr->nxtpkt) + (hdr.next-ctlr->pstart) - 1;
390*74a4d8c2SCharles.Forsyth 		if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
391*74a4d8c2SCharles.Forsyth 			len--;
392*74a4d8c2SCharles.Forsyth 
393*74a4d8c2SCharles.Forsyth 		len = ((len<<8)|hdr.len0)-4;
394*74a4d8c2SCharles.Forsyth 
395*74a4d8c2SCharles.Forsyth 		/*
396*74a4d8c2SCharles.Forsyth 		 * Chip is badly scrogged, reinitialise the ring.
397*74a4d8c2SCharles.Forsyth 		 */
398*74a4d8c2SCharles.Forsyth 		if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop
399*74a4d8c2SCharles.Forsyth 		  || len < 60 || len > sizeof(Etherpkt)){
400*74a4d8c2SCharles.Forsyth 			print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%lud\n",
401*74a4d8c2SCharles.Forsyth 				hdr.status, hdr.next, hdr.len0, hdr.len1, len);
402*74a4d8c2SCharles.Forsyth 			regw(ctlr, Cr, Page0|RdABORT|Stp);
403*74a4d8c2SCharles.Forsyth 			ringinit(ctlr);
404*74a4d8c2SCharles.Forsyth 			regw(ctlr, Cr, Page0|RdABORT|Sta);
405*74a4d8c2SCharles.Forsyth 
406*74a4d8c2SCharles.Forsyth 			return;
407*74a4d8c2SCharles.Forsyth 		}
408*74a4d8c2SCharles.Forsyth 
409*74a4d8c2SCharles.Forsyth 		/*
410*74a4d8c2SCharles.Forsyth 		 * If it's a good packet read it in to the software buffer.
411*74a4d8c2SCharles.Forsyth 		 * If the packet wraps round the hardware ring, read it in
412*74a4d8c2SCharles.Forsyth 		 * two pieces.
413*74a4d8c2SCharles.Forsyth 		 */
414*74a4d8c2SCharles.Forsyth 		ring = &ether->rb[ether->ri];
415*74a4d8c2SCharles.Forsyth 		if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && ring->owner == Interface){
416*74a4d8c2SCharles.Forsyth 			p = ring->pkt;
417*74a4d8c2SCharles.Forsyth 			ring->len = len;
418*74a4d8c2SCharles.Forsyth 			data += sizeof(Hdr);
419*74a4d8c2SCharles.Forsyth 
420*74a4d8c2SCharles.Forsyth 			if((data+len) >= ctlr->pstop*Dp8390BufSz){
421*74a4d8c2SCharles.Forsyth 				count = ctlr->pstop*Dp8390BufSz - data;
422*74a4d8c2SCharles.Forsyth 				if(ctlr->ram)
423*74a4d8c2SCharles.Forsyth 					memmove(p, (void*)(ether->mem+data), count);
424*74a4d8c2SCharles.Forsyth 				else
425*74a4d8c2SCharles.Forsyth 					_dp8390read(ctlr, p, data, count);
426*74a4d8c2SCharles.Forsyth 				p += count;
427*74a4d8c2SCharles.Forsyth 				data = ctlr->pstart*Dp8390BufSz;
428*74a4d8c2SCharles.Forsyth 				len -= count;
429*74a4d8c2SCharles.Forsyth 			}
430*74a4d8c2SCharles.Forsyth 			if(len){
431*74a4d8c2SCharles.Forsyth 				if(ctlr->ram)
432*74a4d8c2SCharles.Forsyth 					memmove(p, (void*)(ether->mem+data), len);
433*74a4d8c2SCharles.Forsyth 				else
434*74a4d8c2SCharles.Forsyth 					_dp8390read(ctlr, p, data, len);
435*74a4d8c2SCharles.Forsyth 			}
436*74a4d8c2SCharles.Forsyth 
437*74a4d8c2SCharles.Forsyth 			/*
438*74a4d8c2SCharles.Forsyth 			 * Copy the packet to whoever wants it.
439*74a4d8c2SCharles.Forsyth 			 */
440*74a4d8c2SCharles.Forsyth 			ring->owner = Host;
441*74a4d8c2SCharles.Forsyth 			ether->ri = NEXT(ether->ri, ether->nrb);
442*74a4d8c2SCharles.Forsyth 		}
443*74a4d8c2SCharles.Forsyth 
444*74a4d8c2SCharles.Forsyth 		/*
445*74a4d8c2SCharles.Forsyth 		 * Finished with this packet, update the
446*74a4d8c2SCharles.Forsyth 		 * hardware and software ring pointers.
447*74a4d8c2SCharles.Forsyth 		 */
448*74a4d8c2SCharles.Forsyth 		ctlr->nxtpkt = hdr.next;
449*74a4d8c2SCharles.Forsyth 
450*74a4d8c2SCharles.Forsyth 		hdr.next--;
451*74a4d8c2SCharles.Forsyth 		if(hdr.next < ctlr->pstart)
452*74a4d8c2SCharles.Forsyth 			hdr.next = ctlr->pstop-1;
453*74a4d8c2SCharles.Forsyth 		regw(ctlr, Bnry, hdr.next);
454*74a4d8c2SCharles.Forsyth 	}
455*74a4d8c2SCharles.Forsyth }
456*74a4d8c2SCharles.Forsyth 
457*74a4d8c2SCharles.Forsyth static void
txstart(Ether * ether)458*74a4d8c2SCharles.Forsyth txstart(Ether* ether)
459*74a4d8c2SCharles.Forsyth {
460*74a4d8c2SCharles.Forsyth 	int len;
461*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
462*74a4d8c2SCharles.Forsyth 	RingBuf *ring;
463*74a4d8c2SCharles.Forsyth 	uchar minpkt[ETHERMINTU], *rp;
464*74a4d8c2SCharles.Forsyth 
465*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
466*74a4d8c2SCharles.Forsyth 
467*74a4d8c2SCharles.Forsyth 	/*
468*74a4d8c2SCharles.Forsyth 	 * This routine is called both from the top level and from interrupt
469*74a4d8c2SCharles.Forsyth 	 * level and expects to be called with ctlr already locked.
470*74a4d8c2SCharles.Forsyth 	 */
471*74a4d8c2SCharles.Forsyth 	if(ether->tbusy)
472*74a4d8c2SCharles.Forsyth 		return;
473*74a4d8c2SCharles.Forsyth 	ring = &ether->tb[ether->ti];
474*74a4d8c2SCharles.Forsyth 	if(ring->owner != Interface)
475*74a4d8c2SCharles.Forsyth 		return;
476*74a4d8c2SCharles.Forsyth 
477*74a4d8c2SCharles.Forsyth 	/*
478*74a4d8c2SCharles.Forsyth 	 * Make sure the packet is of minimum length;
479*74a4d8c2SCharles.Forsyth 	 * copy it to the card's memory by the appropriate means;
480*74a4d8c2SCharles.Forsyth 	 * start the transmission.
481*74a4d8c2SCharles.Forsyth 	 */
482*74a4d8c2SCharles.Forsyth 	len = ring->len;
483*74a4d8c2SCharles.Forsyth 	rp = ring->pkt;
484*74a4d8c2SCharles.Forsyth 	if(len < ETHERMINTU){
485*74a4d8c2SCharles.Forsyth 		rp = minpkt;
486*74a4d8c2SCharles.Forsyth 		memmove(rp, ring->pkt, len);
487*74a4d8c2SCharles.Forsyth 		memset(rp+len, 0, ETHERMINTU-len);
488*74a4d8c2SCharles.Forsyth 		len = ETHERMINTU;
489*74a4d8c2SCharles.Forsyth 	}
490*74a4d8c2SCharles.Forsyth 
491*74a4d8c2SCharles.Forsyth 	if(ctlr->ram)
492*74a4d8c2SCharles.Forsyth 		memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len);
493*74a4d8c2SCharles.Forsyth 	else
494*74a4d8c2SCharles.Forsyth 		dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len);
495*74a4d8c2SCharles.Forsyth 
496*74a4d8c2SCharles.Forsyth 	regw(ctlr, Tbcr0, len & 0xFF);
497*74a4d8c2SCharles.Forsyth 	regw(ctlr, Tbcr1, (len>>8) & 0xFF);
498*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
499*74a4d8c2SCharles.Forsyth 
500*74a4d8c2SCharles.Forsyth 	ether->tbusy = 1;
501*74a4d8c2SCharles.Forsyth }
502*74a4d8c2SCharles.Forsyth 
503*74a4d8c2SCharles.Forsyth static void
transmit(Ether * ether)504*74a4d8c2SCharles.Forsyth transmit(Ether* ether)
505*74a4d8c2SCharles.Forsyth {
506*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
507*74a4d8c2SCharles.Forsyth 
508*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
509*74a4d8c2SCharles.Forsyth 
510*74a4d8c2SCharles.Forsyth 	ilock(ctlr);
511*74a4d8c2SCharles.Forsyth 	txstart(ether);
512*74a4d8c2SCharles.Forsyth 	iunlock(ctlr);
513*74a4d8c2SCharles.Forsyth }
514*74a4d8c2SCharles.Forsyth 
515*74a4d8c2SCharles.Forsyth static void
overflow(Ether * ether)516*74a4d8c2SCharles.Forsyth overflow(Ether *ether)
517*74a4d8c2SCharles.Forsyth {
518*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
519*74a4d8c2SCharles.Forsyth 	uchar txp;
520*74a4d8c2SCharles.Forsyth 	int resend;
521*74a4d8c2SCharles.Forsyth 
522*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
523*74a4d8c2SCharles.Forsyth 
524*74a4d8c2SCharles.Forsyth 	/*
525*74a4d8c2SCharles.Forsyth 	 * The following procedure is taken from the DP8390[12D] datasheet,
526*74a4d8c2SCharles.Forsyth 	 * it seems pretty adamant that this is what has to be done.
527*74a4d8c2SCharles.Forsyth 	 */
528*74a4d8c2SCharles.Forsyth 	txp = regr(ctlr, Cr) & Txp;
529*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdABORT|Stp);
530*74a4d8c2SCharles.Forsyth 	delay(2);
531*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rbcr0, 0);
532*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rbcr1, 0);
533*74a4d8c2SCharles.Forsyth 
534*74a4d8c2SCharles.Forsyth 	resend = 0;
535*74a4d8c2SCharles.Forsyth 	if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0)
536*74a4d8c2SCharles.Forsyth 		resend = 1;
537*74a4d8c2SCharles.Forsyth 
538*74a4d8c2SCharles.Forsyth 	regw(ctlr, Tcr, LpbkNIC);
539*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdABORT|Sta);
540*74a4d8c2SCharles.Forsyth 	receive(ether);
541*74a4d8c2SCharles.Forsyth 	regw(ctlr, Isr, Ovw);
542*74a4d8c2SCharles.Forsyth 	regw(ctlr, Tcr, LpbkNORMAL);
543*74a4d8c2SCharles.Forsyth 
544*74a4d8c2SCharles.Forsyth 	if(resend)
545*74a4d8c2SCharles.Forsyth 		regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
546*74a4d8c2SCharles.Forsyth }
547*74a4d8c2SCharles.Forsyth 
548*74a4d8c2SCharles.Forsyth static void
interrupt(Ureg *,void * arg)549*74a4d8c2SCharles.Forsyth interrupt(Ureg*, void* arg)
550*74a4d8c2SCharles.Forsyth {
551*74a4d8c2SCharles.Forsyth 	Ether *ether;
552*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
553*74a4d8c2SCharles.Forsyth 	RingBuf *ring;
554*74a4d8c2SCharles.Forsyth 	uchar isr, r;
555*74a4d8c2SCharles.Forsyth 
556*74a4d8c2SCharles.Forsyth 	ether = arg;
557*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
558*74a4d8c2SCharles.Forsyth 
559*74a4d8c2SCharles.Forsyth 	/*
560*74a4d8c2SCharles.Forsyth 	 * While there is something of interest,
561*74a4d8c2SCharles.Forsyth 	 * clear all the interrupts and process.
562*74a4d8c2SCharles.Forsyth 	 */
563*74a4d8c2SCharles.Forsyth 	ilock(ctlr);
564*74a4d8c2SCharles.Forsyth 	regw(ctlr, Imr, 0x00);
565*74a4d8c2SCharles.Forsyth 	while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){
566*74a4d8c2SCharles.Forsyth 		if(isr & Ovw){
567*74a4d8c2SCharles.Forsyth 			overflow(ether);
568*74a4d8c2SCharles.Forsyth 			regw(ctlr, Isr, Ovw);
569*74a4d8c2SCharles.Forsyth 		}
570*74a4d8c2SCharles.Forsyth 
571*74a4d8c2SCharles.Forsyth 		/*
572*74a4d8c2SCharles.Forsyth 		 * Packets have been received.
573*74a4d8c2SCharles.Forsyth 		 * Take a spin round the ring.
574*74a4d8c2SCharles.Forsyth 		 */
575*74a4d8c2SCharles.Forsyth 		if(isr & (Rxe|Prx)){
576*74a4d8c2SCharles.Forsyth 			receive(ether);
577*74a4d8c2SCharles.Forsyth 			regw(ctlr, Isr, Rxe|Prx);
578*74a4d8c2SCharles.Forsyth 		}
579*74a4d8c2SCharles.Forsyth 
580*74a4d8c2SCharles.Forsyth 		/*
581*74a4d8c2SCharles.Forsyth 		 * A packet completed transmission, successfully or
582*74a4d8c2SCharles.Forsyth 		 * not. Start transmission on the next buffered packet,
583*74a4d8c2SCharles.Forsyth 		 * and wake the output routine.
584*74a4d8c2SCharles.Forsyth 		 */
585*74a4d8c2SCharles.Forsyth 		if(isr & (Txe|Ptx)){
586*74a4d8c2SCharles.Forsyth 			r = regr(ctlr, Tsr);
587*74a4d8c2SCharles.Forsyth 			if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){
588*74a4d8c2SCharles.Forsyth 				print("dp8390: Tsr#%2.2ux|", r);
589*74a4d8c2SCharles.Forsyth 			}
590*74a4d8c2SCharles.Forsyth 
591*74a4d8c2SCharles.Forsyth 			regw(ctlr, Isr, Txe|Ptx);
592*74a4d8c2SCharles.Forsyth 
593*74a4d8c2SCharles.Forsyth 			ring = &ether->tb[ether->ti];
594*74a4d8c2SCharles.Forsyth 			ring->owner = Host;
595*74a4d8c2SCharles.Forsyth 			ether->ti = NEXT(ether->ti, ether->ntb);
596*74a4d8c2SCharles.Forsyth 			ether->tbusy = 0;
597*74a4d8c2SCharles.Forsyth 			txstart(ether);
598*74a4d8c2SCharles.Forsyth 		}
599*74a4d8c2SCharles.Forsyth 
600*74a4d8c2SCharles.Forsyth 		if(isr & Cnt){
601*74a4d8c2SCharles.Forsyth 			regr(ctlr, Cntr0);
602*74a4d8c2SCharles.Forsyth 			regr(ctlr, Cntr1);
603*74a4d8c2SCharles.Forsyth 			regr(ctlr, Cntr2);
604*74a4d8c2SCharles.Forsyth 			regw(ctlr, Isr, Cnt);
605*74a4d8c2SCharles.Forsyth 		}
606*74a4d8c2SCharles.Forsyth 	}
607*74a4d8c2SCharles.Forsyth 	regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
608*74a4d8c2SCharles.Forsyth 	iunlock(ctlr);
609*74a4d8c2SCharles.Forsyth }
610*74a4d8c2SCharles.Forsyth 
611*74a4d8c2SCharles.Forsyth static void
attach(Ether * ether)612*74a4d8c2SCharles.Forsyth attach(Ether* ether)
613*74a4d8c2SCharles.Forsyth {
614*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
615*74a4d8c2SCharles.Forsyth 	uchar r;
616*74a4d8c2SCharles.Forsyth 
617*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
618*74a4d8c2SCharles.Forsyth 
619*74a4d8c2SCharles.Forsyth 	/*
620*74a4d8c2SCharles.Forsyth 	 * Enable the chip for transmit/receive.
621*74a4d8c2SCharles.Forsyth 	 * The init routine leaves the chip in monitor
622*74a4d8c2SCharles.Forsyth 	 * mode. Clear the missed-packet counter, it
623*74a4d8c2SCharles.Forsyth 	 * increments while in monitor mode.
624*74a4d8c2SCharles.Forsyth 	 * Sometimes there's an interrupt pending at this
625*74a4d8c2SCharles.Forsyth 	 * point but there's nothing in the Isr, so
626*74a4d8c2SCharles.Forsyth 	 * any pending interrupts are cleared and the
627*74a4d8c2SCharles.Forsyth 	 * mask of acceptable interrupts is enabled here.
628*74a4d8c2SCharles.Forsyth 	 */
629*74a4d8c2SCharles.Forsyth 	r = Ab;
630*74a4d8c2SCharles.Forsyth 	ilock(ctlr);
631*74a4d8c2SCharles.Forsyth 	regw(ctlr, Isr, 0xFF);
632*74a4d8c2SCharles.Forsyth 	regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
633*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rcr, r);
634*74a4d8c2SCharles.Forsyth 	r = regr(ctlr, Cntr2);
635*74a4d8c2SCharles.Forsyth 	regw(ctlr, Tcr, LpbkNORMAL);
636*74a4d8c2SCharles.Forsyth 	iunlock(ctlr);
637*74a4d8c2SCharles.Forsyth 	USED(r);
638*74a4d8c2SCharles.Forsyth }
639*74a4d8c2SCharles.Forsyth 
640*74a4d8c2SCharles.Forsyth static void
detach(Ether * ether)641*74a4d8c2SCharles.Forsyth detach(Ether* ether)
642*74a4d8c2SCharles.Forsyth {
643*74a4d8c2SCharles.Forsyth 	int timo;
644*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
645*74a4d8c2SCharles.Forsyth 
646*74a4d8c2SCharles.Forsyth 	/*
647*74a4d8c2SCharles.Forsyth 	 * Stop the chip. Set the Stp bit and wait for the chip
648*74a4d8c2SCharles.Forsyth 	 * to finish whatever was on its tiny mind before it sets
649*74a4d8c2SCharles.Forsyth 	 * the Rst bit.
650*74a4d8c2SCharles.Forsyth 	 * The timeout is needed because there may not be a real
651*74a4d8c2SCharles.Forsyth 	 * chip there if this is called when probing for a device
652*74a4d8c2SCharles.Forsyth 	 * at boot.
653*74a4d8c2SCharles.Forsyth 	 */
654*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
655*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdABORT|Stp);
656*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rbcr0, 0);
657*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rbcr1, 0);
658*74a4d8c2SCharles.Forsyth 	for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--)
659*74a4d8c2SCharles.Forsyth 			;
660*74a4d8c2SCharles.Forsyth }
661*74a4d8c2SCharles.Forsyth 
662*74a4d8c2SCharles.Forsyth int
dp8390reset(Ether * ether)663*74a4d8c2SCharles.Forsyth dp8390reset(Ether* ether)
664*74a4d8c2SCharles.Forsyth {
665*74a4d8c2SCharles.Forsyth 	Dp8390 *ctlr;
666*74a4d8c2SCharles.Forsyth 
667*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
668*74a4d8c2SCharles.Forsyth 
669*74a4d8c2SCharles.Forsyth 	/*
670*74a4d8c2SCharles.Forsyth 	 * This is the initialisation procedure described
671*74a4d8c2SCharles.Forsyth 	 * as 'mandatory' in the datasheet, with references
672*74a4d8c2SCharles.Forsyth 	 * to the 3C503 technical reference manual.
673*74a4d8c2SCharles.Forsyth 	 */
674*74a4d8c2SCharles.Forsyth 	detach(ether);
675*74a4d8c2SCharles.Forsyth 	if(ctlr->width != 1)
676*74a4d8c2SCharles.Forsyth 		regw(ctlr, Dcr, Ft4WORD|Ls|Wts);
677*74a4d8c2SCharles.Forsyth 	else
678*74a4d8c2SCharles.Forsyth 		regw(ctlr, Dcr, Ft4WORD|Ls);
679*74a4d8c2SCharles.Forsyth 
680*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rbcr0, 0);
681*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rbcr1, 0);
682*74a4d8c2SCharles.Forsyth 
683*74a4d8c2SCharles.Forsyth 	regw(ctlr, Tcr, LpbkNIC);
684*74a4d8c2SCharles.Forsyth 	regw(ctlr, Rcr, Mon);
685*74a4d8c2SCharles.Forsyth 
686*74a4d8c2SCharles.Forsyth 	/*
687*74a4d8c2SCharles.Forsyth 	 * Init the ring hardware and software ring pointers.
688*74a4d8c2SCharles.Forsyth 	 * Can't initialise ethernet address as it may not be
689*74a4d8c2SCharles.Forsyth 	 * known yet.
690*74a4d8c2SCharles.Forsyth 	 */
691*74a4d8c2SCharles.Forsyth 	ringinit(ctlr);
692*74a4d8c2SCharles.Forsyth 	regw(ctlr, Tpsr, ctlr->tstart);
693*74a4d8c2SCharles.Forsyth 
694*74a4d8c2SCharles.Forsyth 	/*
695*74a4d8c2SCharles.Forsyth 	 * Clear any pending interrupts and mask then all off.
696*74a4d8c2SCharles.Forsyth 	 */
697*74a4d8c2SCharles.Forsyth 	regw(ctlr, Isr, 0xFF);
698*74a4d8c2SCharles.Forsyth 	regw(ctlr, Imr, 0);
699*74a4d8c2SCharles.Forsyth 
700*74a4d8c2SCharles.Forsyth 	/*
701*74a4d8c2SCharles.Forsyth 	 * Leave the chip initialised,
702*74a4d8c2SCharles.Forsyth 	 * but in monitor mode.
703*74a4d8c2SCharles.Forsyth 	 */
704*74a4d8c2SCharles.Forsyth 	regw(ctlr, Cr, Page0|RdABORT|Sta);
705*74a4d8c2SCharles.Forsyth 
706*74a4d8c2SCharles.Forsyth 	/*
707*74a4d8c2SCharles.Forsyth 	 * Set up the software configuration.
708*74a4d8c2SCharles.Forsyth 	 */
709*74a4d8c2SCharles.Forsyth 	ether->attach = attach;
710*74a4d8c2SCharles.Forsyth 	ether->transmit = transmit;
711*74a4d8c2SCharles.Forsyth 	ether->interrupt = interrupt;
712*74a4d8c2SCharles.Forsyth 	ether->detach = detach;
713*74a4d8c2SCharles.Forsyth 
714*74a4d8c2SCharles.Forsyth 	return 0;
715*74a4d8c2SCharles.Forsyth }
716