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 = ðer->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 = ðer->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 = ðer->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