1bd389b36SDavid du Colombier /*
27dd7cddfSDavid du Colombier * National Semiconductor DP8390 and clone
3bd389b36SDavid du Colombier * Network Interface Controller.
4bd389b36SDavid du Colombier */
5bd389b36SDavid du Colombier #include "u.h"
6bd389b36SDavid du Colombier #include "../port/lib.h"
7bd389b36SDavid du Colombier #include "mem.h"
8bd389b36SDavid du Colombier #include "dat.h"
9bd389b36SDavid du Colombier #include "fns.h"
10bd389b36SDavid du Colombier #include "io.h"
117dd7cddfSDavid du Colombier #include "../port/error.h"
127dd7cddfSDavid du Colombier #include "../port/netif.h"
13bd389b36SDavid du Colombier
147dd7cddfSDavid du Colombier #include "etherif.h"
157dd7cddfSDavid du Colombier #include "ether8390.h"
16bd389b36SDavid du Colombier
177dd7cddfSDavid du Colombier enum { /* NIC core registers */
18bd389b36SDavid du Colombier Cr = 0x00, /* command register, all pages */
19bd389b36SDavid du Colombier
207dd7cddfSDavid du Colombier /* Page 0, read */
21bd389b36SDavid du Colombier Clda0 = 0x01, /* current local DMA address 0 */
22bd389b36SDavid du Colombier Clda1 = 0x02, /* current local DMA address 1 */
23bd389b36SDavid du Colombier Bnry = 0x03, /* boundary pointer (R/W) */
24bd389b36SDavid du Colombier Tsr = 0x04, /* transmit status register */
25bd389b36SDavid du Colombier Ncr = 0x05, /* number of collisions register */
26bd389b36SDavid du Colombier Fifo = 0x06, /* FIFO */
27bd389b36SDavid du Colombier Isr = 0x07, /* interrupt status register (R/W) */
28bd389b36SDavid du Colombier Crda0 = 0x08, /* current remote DMA address 0 */
29219b2ee8SDavid du Colombier Crda1 = 0x09, /* current remote DMA address 1 */
30bd389b36SDavid du Colombier Rsr = 0x0C, /* receive status register */
31e288d156SDavid du Colombier Ref0 = 0x0D, /* frame alignment errors */
32e288d156SDavid du Colombier Ref1 = 0x0E, /* CRC errors */
33e288d156SDavid du Colombier Ref2 = 0x0F, /* missed packet errors */
34bd389b36SDavid du Colombier
357dd7cddfSDavid du Colombier /* Page 0, write */
36bd389b36SDavid du Colombier Pstart = 0x01, /* page start register */
37bd389b36SDavid du Colombier Pstop = 0x02, /* page stop register */
38bd389b36SDavid du Colombier Tpsr = 0x04, /* transmit page start address */
39bd389b36SDavid du Colombier Tbcr0 = 0x05, /* transmit byte count register 0 */
40bd389b36SDavid du Colombier Tbcr1 = 0x06, /* transmit byte count register 1 */
41bd389b36SDavid du Colombier Rsar0 = 0x08, /* remote start address register 0 */
42bd389b36SDavid du Colombier Rsar1 = 0x09, /* remote start address register 1 */
43bd389b36SDavid du Colombier Rbcr0 = 0x0A, /* remote byte count register 0 */
44bd389b36SDavid du Colombier Rbcr1 = 0x0B, /* remote byte count register 1 */
45bd389b36SDavid du Colombier Rcr = 0x0C, /* receive configuration register */
46bd389b36SDavid du Colombier Tcr = 0x0D, /* transmit configuration register */
47bd389b36SDavid du Colombier Dcr = 0x0E, /* data configuration register */
48bd389b36SDavid du Colombier Imr = 0x0F, /* interrupt mask */
49bd389b36SDavid du Colombier
507dd7cddfSDavid du Colombier /* Page 1, read/write */
51bd389b36SDavid du Colombier Par0 = 0x01, /* physical address register 0 */
52bd389b36SDavid du Colombier Curr = 0x07, /* current page register */
53bd389b36SDavid du Colombier Mar0 = 0x08, /* multicast address register 0 */
54bd389b36SDavid du Colombier };
55bd389b36SDavid du Colombier
567dd7cddfSDavid du Colombier enum { /* Cr */
577dd7cddfSDavid du Colombier Stp = 0x01, /* stop */
587dd7cddfSDavid du Colombier Sta = 0x02, /* start */
597dd7cddfSDavid du Colombier Txp = 0x04, /* transmit packet */
607dd7cddfSDavid du Colombier Rd0 = 0x08, /* remote DMA command */
617dd7cddfSDavid du Colombier Rd1 = 0x10,
627dd7cddfSDavid du Colombier Rd2 = 0x20,
637dd7cddfSDavid du Colombier RdREAD = Rd0, /* remote read */
647dd7cddfSDavid du Colombier RdWRITE = Rd1, /* remote write */
657dd7cddfSDavid du Colombier RdSEND = Rd1|Rd0, /* send packet */
667dd7cddfSDavid du Colombier RdABORT = Rd2, /* abort/complete remote DMA */
677dd7cddfSDavid du Colombier Ps0 = 0x40, /* page select */
687dd7cddfSDavid du Colombier Ps1 = 0x80,
697dd7cddfSDavid du Colombier Page0 = 0x00,
707dd7cddfSDavid du Colombier Page1 = Ps0,
717dd7cddfSDavid du Colombier Page2 = Ps1,
727dd7cddfSDavid du Colombier };
737dd7cddfSDavid du Colombier
747dd7cddfSDavid du Colombier enum { /* Isr/Imr */
75bd389b36SDavid du Colombier Prx = 0x01, /* packet received */
76bd389b36SDavid du Colombier Ptx = 0x02, /* packet transmitted */
77bd389b36SDavid du Colombier Rxe = 0x04, /* receive error */
78bd389b36SDavid du Colombier Txe = 0x08, /* transmit error */
79bd389b36SDavid du Colombier Ovw = 0x10, /* overwrite warning */
80bd389b36SDavid du Colombier Cnt = 0x20, /* counter overflow */
81bd389b36SDavid du Colombier Rdc = 0x40, /* remote DMA complete */
82bd389b36SDavid du Colombier Rst = 0x80, /* reset status */
83bd389b36SDavid du Colombier };
84bd389b36SDavid du Colombier
857dd7cddfSDavid du Colombier enum { /* Dcr */
86bd389b36SDavid du Colombier Wts = 0x01, /* word transfer select */
87bd389b36SDavid du Colombier Bos = 0x02, /* byte order select */
88bd389b36SDavid du Colombier Las = 0x04, /* long address select */
89bd389b36SDavid du Colombier Ls = 0x08, /* loopback select */
90bd389b36SDavid du Colombier Arm = 0x10, /* auto-initialise remote */
917dd7cddfSDavid du Colombier Ft0 = 0x20, /* FIFO threshold select */
927dd7cddfSDavid du Colombier Ft1 = 0x40,
937dd7cddfSDavid du Colombier Ft1WORD = 0x00,
947dd7cddfSDavid du Colombier Ft2WORD = Ft0,
957dd7cddfSDavid du Colombier Ft4WORD = Ft1,
967dd7cddfSDavid du Colombier Ft6WORD = Ft1|Ft0,
97bd389b36SDavid du Colombier };
98bd389b36SDavid du Colombier
997dd7cddfSDavid du Colombier enum { /* Tcr */
100bd389b36SDavid du Colombier Crc = 0x01, /* inhibit CRC */
1017dd7cddfSDavid du Colombier Lb0 = 0x02, /* encoded loopback control */
1027dd7cddfSDavid du Colombier Lb1 = 0x04,
1037dd7cddfSDavid du Colombier LpbkNORMAL = 0x00, /* normal operation */
1047dd7cddfSDavid du Colombier LpbkNIC = Lb0, /* internal NIC module loopback */
1057dd7cddfSDavid du Colombier LpbkENDEC = Lb1, /* internal ENDEC module loopback */
1067dd7cddfSDavid du Colombier LpbkEXTERNAL = Lb1|Lb0, /* external loopback */
107bd389b36SDavid du Colombier Atd = 0x08, /* auto transmit disable */
108bd389b36SDavid du Colombier Ofst = 0x10, /* collision offset enable */
109bd389b36SDavid du Colombier };
110bd389b36SDavid du Colombier
1117dd7cddfSDavid du Colombier enum { /* Tsr */
112bd389b36SDavid du Colombier Ptxok = 0x01, /* packet transmitted */
113bd389b36SDavid du Colombier Col = 0x04, /* transmit collided */
114bd389b36SDavid du Colombier Abt = 0x08, /* tranmit aborted */
115bd389b36SDavid du Colombier Crs = 0x10, /* carrier sense lost */
116bd389b36SDavid du Colombier Fu = 0x20, /* FIFO underrun */
117bd389b36SDavid du Colombier Cdh = 0x40, /* CD heartbeat */
118bd389b36SDavid du Colombier Owc = 0x80, /* out of window collision */
119bd389b36SDavid du Colombier };
120bd389b36SDavid du Colombier
1217dd7cddfSDavid du Colombier enum { /* Rcr */
122bd389b36SDavid du Colombier Sep = 0x01, /* save errored packets */
123bd389b36SDavid du Colombier Ar = 0x02, /* accept runt packets */
124bd389b36SDavid du Colombier Ab = 0x04, /* accept broadcast */
125bd389b36SDavid du Colombier Am = 0x08, /* accept multicast */
126bd389b36SDavid du Colombier Pro = 0x10, /* promiscuous physical */
127bd389b36SDavid du Colombier Mon = 0x20, /* monitor mode */
128bd389b36SDavid du Colombier };
129bd389b36SDavid du Colombier
1307dd7cddfSDavid du Colombier enum { /* Rsr */
131bd389b36SDavid du Colombier Prxok = 0x01, /* packet received intact */
132bd389b36SDavid du Colombier Crce = 0x02, /* CRC error */
133bd389b36SDavid du Colombier Fae = 0x04, /* frame alignment error */
134bd389b36SDavid du Colombier Fo = 0x08, /* FIFO overrun */
135bd389b36SDavid du Colombier Mpa = 0x10, /* missed packet */
136bd389b36SDavid du Colombier Phy = 0x20, /* physical/multicast address */
137bd389b36SDavid du Colombier Dis = 0x40, /* receiver disabled */
138bd389b36SDavid du Colombier Dfr = 0x80, /* deferring */
139bd389b36SDavid du Colombier };
140bd389b36SDavid du Colombier
14159c21d95SDavid du Colombier typedef struct Hdr Hdr;
14259c21d95SDavid du Colombier struct Hdr {
143bd389b36SDavid du Colombier uchar status;
144bd389b36SDavid du Colombier uchar next;
145bd389b36SDavid du Colombier uchar len0;
146bd389b36SDavid du Colombier uchar len1;
14759c21d95SDavid du Colombier };
148bd389b36SDavid du Colombier
149bd389b36SDavid du Colombier void
dp8390getea(Ether * ether,uchar * ea)1507dd7cddfSDavid du Colombier dp8390getea(Ether* ether, uchar* ea)
151bd389b36SDavid du Colombier {
1527dd7cddfSDavid du Colombier Dp8390 *ctlr;
153bd389b36SDavid du Colombier uchar cr;
154bd389b36SDavid du Colombier int i;
155bd389b36SDavid du Colombier
1567dd7cddfSDavid du Colombier ctlr = ether->ctlr;
1577dd7cddfSDavid du Colombier
158bd389b36SDavid du Colombier /*
1597dd7cddfSDavid du Colombier * Get the ethernet address from the chip.
160bd389b36SDavid du Colombier * Take care to restore the command register
1617dd7cddfSDavid du Colombier * afterwards.
162bd389b36SDavid du Colombier */
1637dd7cddfSDavid du Colombier ilock(ctlr);
1647dd7cddfSDavid du Colombier cr = regr(ctlr, Cr) & ~Txp;
1657dd7cddfSDavid du Colombier regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
1667dd7cddfSDavid du Colombier for(i = 0; i < Eaddrlen; i++)
1677dd7cddfSDavid du Colombier ea[i] = regr(ctlr, Par0+i);
1687dd7cddfSDavid du Colombier regw(ctlr, Cr, cr);
1697dd7cddfSDavid du Colombier iunlock(ctlr);
170219b2ee8SDavid du Colombier }
171219b2ee8SDavid du Colombier
172219b2ee8SDavid du Colombier void
dp8390setea(Ether * ether)1737dd7cddfSDavid du Colombier dp8390setea(Ether* ether)
174219b2ee8SDavid du Colombier {
175219b2ee8SDavid du Colombier int i;
1767dd7cddfSDavid du Colombier uchar cr;
1777dd7cddfSDavid du Colombier Dp8390 *ctlr;
178219b2ee8SDavid du Colombier
1797dd7cddfSDavid du Colombier ctlr = ether->ctlr;
1807dd7cddfSDavid du Colombier
181219b2ee8SDavid du Colombier /*
182219b2ee8SDavid du Colombier * Set the ethernet address into the chip.
183219b2ee8SDavid du Colombier * Take care to restore the command register
1847dd7cddfSDavid du Colombier * afterwards. Don't care about multicast
1857dd7cddfSDavid du Colombier * addresses as multicast is never enabled
1867dd7cddfSDavid du Colombier * (currently).
187219b2ee8SDavid du Colombier */
1887dd7cddfSDavid du Colombier ilock(ctlr);
1897dd7cddfSDavid du Colombier cr = regr(ctlr, Cr) & ~Txp;
1907dd7cddfSDavid du Colombier regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
1917dd7cddfSDavid du Colombier for(i = 0; i < Eaddrlen; i++)
1927dd7cddfSDavid du Colombier regw(ctlr, Par0+i, ether->ea[i]);
1937dd7cddfSDavid du Colombier regw(ctlr, Cr, cr);
1947dd7cddfSDavid du Colombier iunlock(ctlr);
195bd389b36SDavid du Colombier }
196bd389b36SDavid du Colombier
1977dd7cddfSDavid du Colombier static void*
_dp8390read(Dp8390 * ctlr,void * to,ulong from,ulong len)1987dd7cddfSDavid du Colombier _dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
199bd389b36SDavid du Colombier {
200bd389b36SDavid du Colombier uchar cr;
201bd389b36SDavid du Colombier int timo;
202bd389b36SDavid du Colombier
203bd389b36SDavid du Colombier /*
204219b2ee8SDavid du Colombier * Read some data at offset 'from' in the card's memory
205bd389b36SDavid du Colombier * using the DP8390 remote DMA facility, and place it at
206bd389b36SDavid du Colombier * 'to' in main memory, via the I/O data port.
207bd389b36SDavid du Colombier */
2087dd7cddfSDavid du Colombier cr = regr(ctlr, Cr) & ~Txp;
2097dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Sta);
2107dd7cddfSDavid du Colombier regw(ctlr, Isr, Rdc);
211bd389b36SDavid du Colombier
212bd389b36SDavid du Colombier /*
213bd389b36SDavid du Colombier * Set up the remote DMA address and count.
214bd389b36SDavid du Colombier */
2157dd7cddfSDavid du Colombier len = ROUNDUP(len, ctlr->width);
2167dd7cddfSDavid du Colombier regw(ctlr, Rbcr0, len & 0xFF);
2177dd7cddfSDavid du Colombier regw(ctlr, Rbcr1, (len>>8) & 0xFF);
2187dd7cddfSDavid du Colombier regw(ctlr, Rsar0, from & 0xFF);
2197dd7cddfSDavid du Colombier regw(ctlr, Rsar1, (from>>8) & 0xFF);
220bd389b36SDavid du Colombier
221bd389b36SDavid du Colombier /*
222bd389b36SDavid du Colombier * Start the remote DMA read and suck the data
223bd389b36SDavid du Colombier * out of the I/O port.
224bd389b36SDavid du Colombier */
2257dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdREAD|Sta);
2267dd7cddfSDavid du Colombier rdread(ctlr, to, len);
227bd389b36SDavid du Colombier
228bd389b36SDavid du Colombier /*
229bd389b36SDavid du Colombier * Wait for the remote DMA to complete. The timeout
2307dd7cddfSDavid du Colombier * is necessary because this routine may be called on
231bd389b36SDavid du Colombier * a non-existent chip during initialisation and, due
2327dd7cddfSDavid du Colombier * to the miracles of the bus, it's possible to get this
2337dd7cddfSDavid du Colombier * far and still be talking to a slot full of nothing.
234bd389b36SDavid du Colombier */
2357dd7cddfSDavid du Colombier for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
236bd389b36SDavid du Colombier ;
237bd389b36SDavid du Colombier
2387dd7cddfSDavid du Colombier regw(ctlr, Isr, Rdc);
2397dd7cddfSDavid du Colombier regw(ctlr, Cr, cr);
2407dd7cddfSDavid du Colombier
241bd389b36SDavid du Colombier return to;
242bd389b36SDavid du Colombier }
243bd389b36SDavid du Colombier
244bd389b36SDavid du Colombier void*
dp8390read(Dp8390 * ctlr,void * to,ulong from,ulong len)2457dd7cddfSDavid du Colombier dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
246bd389b36SDavid du Colombier {
2477dd7cddfSDavid du Colombier void *v;
248bd389b36SDavid du Colombier
2497dd7cddfSDavid du Colombier ilock(ctlr);
2507dd7cddfSDavid du Colombier v = _dp8390read(ctlr, to, from, len);
2517dd7cddfSDavid du Colombier iunlock(ctlr);
2527dd7cddfSDavid du Colombier
2537dd7cddfSDavid du Colombier return v;
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier
2567dd7cddfSDavid du Colombier static void*
dp8390write(Dp8390 * ctlr,ulong to,void * from,ulong len)2577dd7cddfSDavid du Colombier dp8390write(Dp8390* ctlr, ulong to, void* from, ulong len)
2587dd7cddfSDavid du Colombier {
2597dd7cddfSDavid du Colombier ulong crda;
2607dd7cddfSDavid du Colombier uchar cr;
2617dd7cddfSDavid du Colombier int timo, width;
2627dd7cddfSDavid du Colombier
263a22b0629SDavid du Colombier top:
264bd389b36SDavid du Colombier /*
265219b2ee8SDavid du Colombier * Write some data to offset 'to' in the card's memory
266bd389b36SDavid du Colombier * using the DP8390 remote DMA facility, reading it at
267bd389b36SDavid du Colombier * 'from' in main memory, via the I/O data port.
268bd389b36SDavid du Colombier */
2697dd7cddfSDavid du Colombier cr = regr(ctlr, Cr) & ~Txp;
2707dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Sta);
2717dd7cddfSDavid du Colombier regw(ctlr, Isr, Rdc);
272219b2ee8SDavid du Colombier
2737dd7cddfSDavid du Colombier len = ROUNDUP(len, ctlr->width);
274bd389b36SDavid du Colombier
275bd389b36SDavid du Colombier /*
276bd389b36SDavid du Colombier * Set up the remote DMA address and count.
2777dd7cddfSDavid du Colombier * This is straight from the DP8390[12D] datasheet,
2787dd7cddfSDavid du Colombier * hence the initial set up for read.
2797dd7cddfSDavid du Colombier * Assumption here that the A7000 EtherV card will
2807dd7cddfSDavid du Colombier * never need a dummyrr.
281bd389b36SDavid du Colombier */
2827dd7cddfSDavid du Colombier if(ctlr->dummyrr && (ctlr->width == 1 || ctlr->width == 2)){
2837dd7cddfSDavid du Colombier if(ctlr->width == 2)
2847dd7cddfSDavid du Colombier width = 1;
2857dd7cddfSDavid du Colombier else
2867dd7cddfSDavid du Colombier width = 0;
2877dd7cddfSDavid du Colombier crda = to-1-width;
2887dd7cddfSDavid du Colombier regw(ctlr, Rbcr0, (len+1+width) & 0xFF);
2897dd7cddfSDavid du Colombier regw(ctlr, Rbcr1, ((len+1+width)>>8) & 0xFF);
2907dd7cddfSDavid du Colombier regw(ctlr, Rsar0, crda & 0xFF);
2917dd7cddfSDavid du Colombier regw(ctlr, Rsar1, (crda>>8) & 0xFF);
2927dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdREAD|Sta);
293bd389b36SDavid du Colombier
294a22b0629SDavid du Colombier for(timo=0;; timo++){
295a22b0629SDavid du Colombier if(timo > 10000){
296a22b0629SDavid du Colombier print("ether8390: dummyrr timeout; assuming nodummyrr\n");
297a22b0629SDavid du Colombier ctlr->dummyrr = 0;
298a22b0629SDavid du Colombier goto top;
299a22b0629SDavid du Colombier }
3007dd7cddfSDavid du Colombier crda = regr(ctlr, Crda0);
3017dd7cddfSDavid du Colombier crda |= regr(ctlr, Crda1)<<8;
302219b2ee8SDavid du Colombier if(crda == to){
303219b2ee8SDavid du Colombier /*
304219b2ee8SDavid du Colombier * Start the remote DMA write and make sure
305219b2ee8SDavid du Colombier * the registers are correct.
306219b2ee8SDavid du Colombier */
3077dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdWRITE|Sta);
308219b2ee8SDavid du Colombier
3097dd7cddfSDavid du Colombier crda = regr(ctlr, Crda0);
3107dd7cddfSDavid du Colombier crda |= regr(ctlr, Crda1)<<8;
311219b2ee8SDavid du Colombier if(crda != to)
3129a747e4fSDavid du Colombier panic("crda write %lud to %lud\n", crda, to);
313219b2ee8SDavid du Colombier
314219b2ee8SDavid du Colombier break;
315219b2ee8SDavid du Colombier }
316219b2ee8SDavid du Colombier }
3177dd7cddfSDavid du Colombier }
3187dd7cddfSDavid du Colombier else{
3197dd7cddfSDavid du Colombier regw(ctlr, Rsar0, to & 0xFF);
3207dd7cddfSDavid du Colombier regw(ctlr, Rsar1, (to>>8) & 0xFF);
3217dd7cddfSDavid du Colombier regw(ctlr, Rbcr0, len & 0xFF);
3227dd7cddfSDavid du Colombier regw(ctlr, Rbcr1, (len>>8) & 0xFF);
3237dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdWRITE|Sta);
3247dd7cddfSDavid du Colombier }
325bd389b36SDavid du Colombier
326bd389b36SDavid du Colombier /*
3277dd7cddfSDavid du Colombier * Pump the data into the I/O port
3287dd7cddfSDavid du Colombier * then wait for the remote DMA to finish.
329bd389b36SDavid du Colombier */
3307dd7cddfSDavid du Colombier rdwrite(ctlr, from, len);
3317dd7cddfSDavid du Colombier for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
332bd389b36SDavid du Colombier ;
333bd389b36SDavid du Colombier
3347dd7cddfSDavid du Colombier regw(ctlr, Isr, Rdc);
3357dd7cddfSDavid du Colombier regw(ctlr, Cr, cr);
3367dd7cddfSDavid du Colombier
337bd389b36SDavid du Colombier return (void*)to;
338bd389b36SDavid du Colombier }
339bd389b36SDavid du Colombier
3407dd7cddfSDavid du Colombier static void
ringinit(Dp8390 * ctlr)3417dd7cddfSDavid du Colombier ringinit(Dp8390* ctlr)
3427dd7cddfSDavid du Colombier {
3437dd7cddfSDavid du Colombier regw(ctlr, Pstart, ctlr->pstart);
3447dd7cddfSDavid du Colombier regw(ctlr, Pstop, ctlr->pstop);
3457dd7cddfSDavid du Colombier regw(ctlr, Bnry, ctlr->pstop-1);
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier regw(ctlr, Cr, Page1|RdABORT|Stp);
3487dd7cddfSDavid du Colombier regw(ctlr, Curr, ctlr->pstart);
3497dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Stp);
3507dd7cddfSDavid du Colombier
3517dd7cddfSDavid du Colombier ctlr->nxtpkt = ctlr->pstart;
3527dd7cddfSDavid du Colombier }
3537dd7cddfSDavid du Colombier
354219b2ee8SDavid du Colombier static uchar
getcurr(Dp8390 * ctlr)3557dd7cddfSDavid du Colombier getcurr(Dp8390* ctlr)
356bd389b36SDavid du Colombier {
357219b2ee8SDavid du Colombier uchar cr, curr;
358bd389b36SDavid du Colombier
3597dd7cddfSDavid du Colombier cr = regr(ctlr, Cr) & ~Txp;
3607dd7cddfSDavid du Colombier regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
3617dd7cddfSDavid du Colombier curr = regr(ctlr, Curr);
3627dd7cddfSDavid du Colombier regw(ctlr, Cr, cr);
3637dd7cddfSDavid du Colombier
364219b2ee8SDavid du Colombier return curr;
365219b2ee8SDavid du Colombier }
366bd389b36SDavid du Colombier
367219b2ee8SDavid du Colombier static void
receive(Ether * ether)3687dd7cddfSDavid du Colombier receive(Ether* ether)
369219b2ee8SDavid du Colombier {
3707dd7cddfSDavid du Colombier Dp8390 *ctlr;
3717dd7cddfSDavid du Colombier uchar curr, *p;
372219b2ee8SDavid du Colombier Hdr hdr;
3737dd7cddfSDavid du Colombier ulong count, data, len;
3747dd7cddfSDavid du Colombier Block *bp;
375219b2ee8SDavid du Colombier
3767dd7cddfSDavid du Colombier ctlr = ether->ctlr;
3777dd7cddfSDavid du Colombier for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){
3787dd7cddfSDavid du Colombier data = ctlr->nxtpkt*Dp8390BufSz;
3797dd7cddfSDavid du Colombier if(ctlr->ram)
3807dd7cddfSDavid du Colombier memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr));
3817dd7cddfSDavid du Colombier else
3827dd7cddfSDavid du Colombier _dp8390read(ctlr, &hdr, data, sizeof(Hdr));
383bd389b36SDavid du Colombier
384bd389b36SDavid du Colombier /*
385219b2ee8SDavid du Colombier * Don't believe the upper byte count, work it
386219b2ee8SDavid du Colombier * out from the software next-page pointer and
387219b2ee8SDavid du Colombier * the current next-page pointer.
388bd389b36SDavid du Colombier */
3897dd7cddfSDavid du Colombier if(hdr.next > ctlr->nxtpkt)
3907dd7cddfSDavid du Colombier len = hdr.next - ctlr->nxtpkt - 1;
391219b2ee8SDavid du Colombier else
3927dd7cddfSDavid du Colombier len = (ctlr->pstop-ctlr->nxtpkt) + (hdr.next-ctlr->pstart) - 1;
393219b2ee8SDavid du Colombier if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
3947dd7cddfSDavid du Colombier len--;
395219b2ee8SDavid du Colombier
3967dd7cddfSDavid du Colombier len = ((len<<8)|hdr.len0)-4;
397219b2ee8SDavid du Colombier
398219b2ee8SDavid du Colombier /*
399219b2ee8SDavid du Colombier * Chip is badly scrogged, reinitialise the ring.
400219b2ee8SDavid du Colombier */
4017dd7cddfSDavid du Colombier if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop
402219b2ee8SDavid du Colombier || len < 60 || len > sizeof(Etherpkt)){
4034de34a7eSDavid du Colombier print("dp8390: H%2.2ux+%2.2ux+%2.2ux+%2.2ux,%lud\n",
404219b2ee8SDavid du Colombier hdr.status, hdr.next, hdr.len0, hdr.len1, len);
4057dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Stp);
4067dd7cddfSDavid du Colombier ringinit(ctlr);
4077dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Sta);
4087dd7cddfSDavid du Colombier
409bd389b36SDavid du Colombier return;
410bd389b36SDavid du Colombier }
411bd389b36SDavid du Colombier
412219b2ee8SDavid du Colombier /*
4137dd7cddfSDavid du Colombier * If it's a good packet read it in to the software buffer.
4147dd7cddfSDavid du Colombier * If the packet wraps round the hardware ring, read it in
4157dd7cddfSDavid du Colombier * two pieces.
416219b2ee8SDavid du Colombier */
4177dd7cddfSDavid du Colombier if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && (bp = iallocb(len))){
4187dd7cddfSDavid du Colombier p = bp->rp;
4197dd7cddfSDavid du Colombier bp->wp = p+len;
420bd389b36SDavid du Colombier data += sizeof(Hdr);
421219b2ee8SDavid du Colombier
4227dd7cddfSDavid du Colombier if((data+len) >= ctlr->pstop*Dp8390BufSz){
4237dd7cddfSDavid du Colombier count = ctlr->pstop*Dp8390BufSz - data;
4247dd7cddfSDavid du Colombier if(ctlr->ram)
4257dd7cddfSDavid du Colombier memmove(p, (void*)(ether->mem+data), count);
4267dd7cddfSDavid du Colombier else
4277dd7cddfSDavid du Colombier _dp8390read(ctlr, p, data, count);
4287dd7cddfSDavid du Colombier p += count;
4297dd7cddfSDavid du Colombier data = ctlr->pstart*Dp8390BufSz;
430219b2ee8SDavid du Colombier len -= count;
431bd389b36SDavid du Colombier }
4327dd7cddfSDavid du Colombier if(len){
4337dd7cddfSDavid du Colombier if(ctlr->ram)
4347dd7cddfSDavid du Colombier memmove(p, (void*)(ether->mem+data), len);
4357dd7cddfSDavid du Colombier else
4367dd7cddfSDavid du Colombier _dp8390read(ctlr, p, data, len);
437bd389b36SDavid du Colombier }
438bd389b36SDavid du Colombier
439219b2ee8SDavid du Colombier /*
4407dd7cddfSDavid du Colombier * Copy the packet to whoever wants it.
4417dd7cddfSDavid du Colombier */
4427dd7cddfSDavid du Colombier etheriq(ether, bp, 1);
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier
4457dd7cddfSDavid du Colombier /*
4467dd7cddfSDavid du Colombier * Finished with this packet, update the
447219b2ee8SDavid du Colombier * hardware and software ring pointers.
448219b2ee8SDavid du Colombier */
4497dd7cddfSDavid du Colombier ctlr->nxtpkt = hdr.next;
450219b2ee8SDavid du Colombier
451219b2ee8SDavid du Colombier hdr.next--;
4527dd7cddfSDavid du Colombier if(hdr.next < ctlr->pstart)
4537dd7cddfSDavid du Colombier hdr.next = ctlr->pstop-1;
4547dd7cddfSDavid du Colombier regw(ctlr, Bnry, hdr.next);
455219b2ee8SDavid du Colombier }
456219b2ee8SDavid du Colombier }
457219b2ee8SDavid du Colombier
4587dd7cddfSDavid du Colombier static void
txstart(Ether * ether)4597dd7cddfSDavid du Colombier txstart(Ether* ether)
4607dd7cddfSDavid du Colombier {
4617dd7cddfSDavid du Colombier int len;
4627dd7cddfSDavid du Colombier Dp8390 *ctlr;
4637dd7cddfSDavid du Colombier Block *bp;
4647dd7cddfSDavid du Colombier uchar minpkt[ETHERMINTU], *rp;
4657dd7cddfSDavid du Colombier
4667dd7cddfSDavid du Colombier ctlr = ether->ctlr;
4677dd7cddfSDavid du Colombier
468219b2ee8SDavid du Colombier /*
4697dd7cddfSDavid du Colombier * This routine is called both from the top level and from interrupt
4707dd7cddfSDavid du Colombier * level and expects to be called with ctlr already locked.
471219b2ee8SDavid du Colombier */
4727dd7cddfSDavid du Colombier if(ctlr->txbusy)
4737dd7cddfSDavid du Colombier return;
4747dd7cddfSDavid du Colombier bp = qget(ether->oq);
4757dd7cddfSDavid du Colombier if(bp == nil)
4767dd7cddfSDavid du Colombier return;
477219b2ee8SDavid du Colombier
4787dd7cddfSDavid du Colombier /*
4797dd7cddfSDavid du Colombier * Make sure the packet is of minimum length;
4807dd7cddfSDavid du Colombier * copy it to the card's memory by the appropriate means;
4817dd7cddfSDavid du Colombier * start the transmission.
4827dd7cddfSDavid du Colombier */
4837dd7cddfSDavid du Colombier len = BLEN(bp);
4847dd7cddfSDavid du Colombier rp = bp->rp;
4857dd7cddfSDavid du Colombier if(len < ETHERMINTU){
4867dd7cddfSDavid du Colombier rp = minpkt;
4877dd7cddfSDavid du Colombier memmove(rp, bp->rp, len);
4887dd7cddfSDavid du Colombier memset(rp+len, 0, ETHERMINTU-len);
4897dd7cddfSDavid du Colombier len = ETHERMINTU;
490bd389b36SDavid du Colombier }
491bd389b36SDavid du Colombier
4927dd7cddfSDavid du Colombier if(ctlr->ram)
4937dd7cddfSDavid du Colombier memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len);
4947dd7cddfSDavid du Colombier else
4957dd7cddfSDavid du Colombier dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len);
4967dd7cddfSDavid du Colombier freeb(bp);
4977dd7cddfSDavid du Colombier
4987dd7cddfSDavid du Colombier regw(ctlr, Tbcr0, len & 0xFF);
4997dd7cddfSDavid du Colombier regw(ctlr, Tbcr1, (len>>8) & 0xFF);
5007dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
5017dd7cddfSDavid du Colombier
5027dd7cddfSDavid du Colombier ether->outpackets++;
5037dd7cddfSDavid du Colombier ctlr->txbusy = 1;
5047dd7cddfSDavid du Colombier }
5057dd7cddfSDavid du Colombier
5067dd7cddfSDavid du Colombier static void
transmit(Ether * ether)5077dd7cddfSDavid du Colombier transmit(Ether* ether)
508bd389b36SDavid du Colombier {
5097dd7cddfSDavid du Colombier Dp8390 *ctlr;
5107dd7cddfSDavid du Colombier
5117dd7cddfSDavid du Colombier ctlr = ether->ctlr;
5127dd7cddfSDavid du Colombier
5137dd7cddfSDavid du Colombier ilock(ctlr);
5147dd7cddfSDavid du Colombier txstart(ether);
5157dd7cddfSDavid du Colombier iunlock(ctlr);
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier
5187dd7cddfSDavid du Colombier static void
overflow(Ether * ether)5197dd7cddfSDavid du Colombier overflow(Ether *ether)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier Dp8390 *ctlr;
522219b2ee8SDavid du Colombier uchar txp;
523219b2ee8SDavid du Colombier int resend;
524219b2ee8SDavid du Colombier
5257dd7cddfSDavid du Colombier ctlr = ether->ctlr;
5267dd7cddfSDavid du Colombier
527219b2ee8SDavid du Colombier /*
528219b2ee8SDavid du Colombier * The following procedure is taken from the DP8390[12D] datasheet,
529219b2ee8SDavid du Colombier * it seems pretty adamant that this is what has to be done.
530219b2ee8SDavid du Colombier */
5317dd7cddfSDavid du Colombier txp = regr(ctlr, Cr) & Txp;
5327dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Stp);
533219b2ee8SDavid du Colombier delay(2);
5347dd7cddfSDavid du Colombier regw(ctlr, Rbcr0, 0);
5357dd7cddfSDavid du Colombier regw(ctlr, Rbcr1, 0);
536219b2ee8SDavid du Colombier
537219b2ee8SDavid du Colombier resend = 0;
5387dd7cddfSDavid du Colombier if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0)
539219b2ee8SDavid du Colombier resend = 1;
540219b2ee8SDavid du Colombier
5417dd7cddfSDavid du Colombier regw(ctlr, Tcr, LpbkNIC);
5427dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Sta);
5437dd7cddfSDavid du Colombier receive(ether);
5447dd7cddfSDavid du Colombier regw(ctlr, Isr, Ovw);
5457dd7cddfSDavid du Colombier regw(ctlr, Tcr, LpbkNORMAL);
546219b2ee8SDavid du Colombier
547219b2ee8SDavid du Colombier if(resend)
5487dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
549219b2ee8SDavid du Colombier }
550219b2ee8SDavid du Colombier
5517dd7cddfSDavid du Colombier static void
interrupt(Ureg *,void * arg)5527dd7cddfSDavid du Colombier interrupt(Ureg*, void* arg)
553219b2ee8SDavid du Colombier {
5547dd7cddfSDavid du Colombier Ether *ether;
5557dd7cddfSDavid du Colombier Dp8390 *ctlr;
556219b2ee8SDavid du Colombier uchar isr, r;
557bd389b36SDavid du Colombier
5587dd7cddfSDavid du Colombier ether = arg;
5597dd7cddfSDavid du Colombier ctlr = ether->ctlr;
5607dd7cddfSDavid du Colombier
561bd389b36SDavid du Colombier /*
562bd389b36SDavid du Colombier * While there is something of interest,
563bd389b36SDavid du Colombier * clear all the interrupts and process.
564bd389b36SDavid du Colombier */
5657dd7cddfSDavid du Colombier ilock(ctlr);
5667dd7cddfSDavid du Colombier regw(ctlr, Imr, 0x00);
5677dd7cddfSDavid du Colombier while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){
568bd389b36SDavid du Colombier if(isr & Ovw){
5697dd7cddfSDavid du Colombier overflow(ether);
5707dd7cddfSDavid du Colombier regw(ctlr, Isr, Ovw);
5717dd7cddfSDavid du Colombier ether->overflows++;
572bd389b36SDavid du Colombier }
573bd389b36SDavid du Colombier
574bd389b36SDavid du Colombier /*
5757dd7cddfSDavid du Colombier * Packets have been received.
5767dd7cddfSDavid du Colombier * Take a spin round the ring.
577bd389b36SDavid du Colombier */
578bd389b36SDavid du Colombier if(isr & (Rxe|Prx)){
5797dd7cddfSDavid du Colombier receive(ether);
5807dd7cddfSDavid du Colombier regw(ctlr, Isr, Rxe|Prx);
581bd389b36SDavid du Colombier }
582bd389b36SDavid du Colombier
583bd389b36SDavid du Colombier /*
584bd389b36SDavid du Colombier * A packet completed transmission, successfully or
585bd389b36SDavid du Colombier * not. Start transmission on the next buffered packet,
586bd389b36SDavid du Colombier * and wake the output routine.
587bd389b36SDavid du Colombier */
588bd389b36SDavid du Colombier if(isr & (Txe|Ptx)){
5897dd7cddfSDavid du Colombier r = regr(ctlr, Tsr);
5907dd7cddfSDavid du Colombier if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){
5914de34a7eSDavid du Colombier print("dp8390: Tsr %#2.2ux", r);
5927dd7cddfSDavid du Colombier ether->oerrs++;
593219b2ee8SDavid du Colombier }
594219b2ee8SDavid du Colombier
5957dd7cddfSDavid du Colombier regw(ctlr, Isr, Txe|Ptx);
596219b2ee8SDavid du Colombier
597219b2ee8SDavid du Colombier if(isr & Ptx)
5987dd7cddfSDavid du Colombier ether->outpackets++;
5997dd7cddfSDavid du Colombier ctlr->txbusy = 0;
6007dd7cddfSDavid du Colombier txstart(ether);
601bd389b36SDavid du Colombier }
602219b2ee8SDavid du Colombier
603219b2ee8SDavid du Colombier if(isr & Cnt){
604e288d156SDavid du Colombier ether->frames += regr(ctlr, Ref0);
605e288d156SDavid du Colombier ether->crcs += regr(ctlr, Ref1);
606e288d156SDavid du Colombier ether->buffs += regr(ctlr, Ref2);
6077dd7cddfSDavid du Colombier regw(ctlr, Isr, Cnt);
608bd389b36SDavid du Colombier }
609bd389b36SDavid du Colombier }
6107dd7cddfSDavid du Colombier regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
6117dd7cddfSDavid du Colombier iunlock(ctlr);
6127dd7cddfSDavid du Colombier }
6137dd7cddfSDavid du Colombier
6147dd7cddfSDavid du Colombier static uchar allmar[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
6157dd7cddfSDavid du Colombier
6167dd7cddfSDavid du Colombier static void
setfilter(Ether * ether,Dp8390 * ctlr)6177dd7cddfSDavid du Colombier setfilter(Ether *ether, Dp8390 *ctlr)
6187dd7cddfSDavid du Colombier {
6197dd7cddfSDavid du Colombier uchar r, cr;
6207dd7cddfSDavid du Colombier int i;
6217dd7cddfSDavid du Colombier uchar *mar;
6227dd7cddfSDavid du Colombier
6237dd7cddfSDavid du Colombier r = Ab;
6247dd7cddfSDavid du Colombier mar = 0;
6257dd7cddfSDavid du Colombier if(ether->prom){
6267dd7cddfSDavid du Colombier r |= Pro|Am;
6277dd7cddfSDavid du Colombier mar = allmar;
6287dd7cddfSDavid du Colombier } else if(ether->nmaddr){
6297dd7cddfSDavid du Colombier r |= Am;
6307dd7cddfSDavid du Colombier mar = ctlr->mar;
6317dd7cddfSDavid du Colombier }
6327dd7cddfSDavid du Colombier if(mar){
6337dd7cddfSDavid du Colombier cr = regr(ctlr, Cr) & ~Txp;
6347dd7cddfSDavid du Colombier regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
6357dd7cddfSDavid du Colombier for(i = 0; i < 8; i++)
6367dd7cddfSDavid du Colombier regw(ctlr, Mar0+i, *(mar++));
6377dd7cddfSDavid du Colombier regw(ctlr, Cr, cr);
6387dd7cddfSDavid du Colombier }
6397dd7cddfSDavid du Colombier regw(ctlr, Rcr, r);
6407dd7cddfSDavid du Colombier }
6417dd7cddfSDavid du Colombier
6427dd7cddfSDavid du Colombier static void
promiscuous(void * arg,int)6437dd7cddfSDavid du Colombier promiscuous(void *arg, int )
6447dd7cddfSDavid du Colombier {
6457dd7cddfSDavid du Colombier Ether *ether;
6467dd7cddfSDavid du Colombier Dp8390 *ctlr;
6477dd7cddfSDavid du Colombier
6487dd7cddfSDavid du Colombier ether = arg;
6497dd7cddfSDavid du Colombier ctlr = ether->ctlr;
6507dd7cddfSDavid du Colombier
6517dd7cddfSDavid du Colombier ilock(ctlr);
6527dd7cddfSDavid du Colombier setfilter(ether, ctlr);
6537dd7cddfSDavid du Colombier iunlock(ctlr);
6547dd7cddfSDavid du Colombier }
6557dd7cddfSDavid du Colombier
6567dd7cddfSDavid du Colombier static void
setbit(Dp8390 * ctlr,int bit,int on)6577dd7cddfSDavid du Colombier setbit(Dp8390 *ctlr, int bit, int on)
6587dd7cddfSDavid du Colombier {
6597dd7cddfSDavid du Colombier int i, h;
6607dd7cddfSDavid du Colombier
6617dd7cddfSDavid du Colombier i = bit/8;
6627dd7cddfSDavid du Colombier h = bit%8;
6637dd7cddfSDavid du Colombier if(on){
6647dd7cddfSDavid du Colombier if(++(ctlr->mref[bit]) == 1)
6657dd7cddfSDavid du Colombier ctlr->mar[i] |= 1<<h;
6667dd7cddfSDavid du Colombier } else {
6677dd7cddfSDavid du Colombier if(--(ctlr->mref[bit]) <= 0){
6687dd7cddfSDavid du Colombier ctlr->mref[bit] = 0;
6697dd7cddfSDavid du Colombier ctlr->mar[i] &= ~(1<<h);
6707dd7cddfSDavid du Colombier }
6717dd7cddfSDavid du Colombier }
6727dd7cddfSDavid du Colombier }
6737dd7cddfSDavid du Colombier
6747dd7cddfSDavid du Colombier static uchar reverse[64];
6757dd7cddfSDavid du Colombier
6767dd7cddfSDavid du Colombier static void
multicast(void * arg,uchar * addr,int on)6777dd7cddfSDavid du Colombier multicast(void* arg, uchar *addr, int on)
6787dd7cddfSDavid du Colombier {
6797dd7cddfSDavid du Colombier Ether *ether;
6807dd7cddfSDavid du Colombier Dp8390 *ctlr;
6817dd7cddfSDavid du Colombier int i;
6827dd7cddfSDavid du Colombier ulong h;
6837dd7cddfSDavid du Colombier
6847dd7cddfSDavid du Colombier ether = arg;
6857dd7cddfSDavid du Colombier ctlr = ether->ctlr;
6867dd7cddfSDavid du Colombier if(reverse[1] == 0){
6877dd7cddfSDavid du Colombier for(i = 0; i < 64; i++)
6887dd7cddfSDavid du Colombier reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1)
6897dd7cddfSDavid du Colombier | ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5);
6907dd7cddfSDavid du Colombier }
6917dd7cddfSDavid du Colombier
6927dd7cddfSDavid du Colombier /*
6937dd7cddfSDavid du Colombier * change filter bits
6947dd7cddfSDavid du Colombier */
6957dd7cddfSDavid du Colombier h = ethercrc(addr, 6);
6967dd7cddfSDavid du Colombier ilock(ctlr);
6977dd7cddfSDavid du Colombier setbit(ctlr, reverse[h&0x3f], on);
6987dd7cddfSDavid du Colombier setfilter(ether, ctlr);
6997dd7cddfSDavid du Colombier iunlock(ctlr);
7007dd7cddfSDavid du Colombier }
7017dd7cddfSDavid du Colombier
7027dd7cddfSDavid du Colombier static void
attach(Ether * ether)7037dd7cddfSDavid du Colombier attach(Ether* ether)
7047dd7cddfSDavid du Colombier {
7057dd7cddfSDavid du Colombier Dp8390 *ctlr;
7067dd7cddfSDavid du Colombier uchar r;
7077dd7cddfSDavid du Colombier
7087dd7cddfSDavid du Colombier ctlr = ether->ctlr;
7097dd7cddfSDavid du Colombier
7107dd7cddfSDavid du Colombier /*
7117dd7cddfSDavid du Colombier * Enable the chip for transmit/receive.
7127dd7cddfSDavid du Colombier * The init routine leaves the chip in monitor
7137dd7cddfSDavid du Colombier * mode. Clear the missed-packet counter, it
7147dd7cddfSDavid du Colombier * increments while in monitor mode.
7157dd7cddfSDavid du Colombier * Sometimes there's an interrupt pending at this
7167dd7cddfSDavid du Colombier * point but there's nothing in the Isr, so
7177dd7cddfSDavid du Colombier * any pending interrupts are cleared and the
7187dd7cddfSDavid du Colombier * mask of acceptable interrupts is enabled here.
7197dd7cddfSDavid du Colombier */
7207dd7cddfSDavid du Colombier r = Ab;
7217dd7cddfSDavid du Colombier if(ether->prom)
7227dd7cddfSDavid du Colombier r |= Pro;
7237dd7cddfSDavid du Colombier if(ether->nmaddr)
7247dd7cddfSDavid du Colombier r |= Am;
7257dd7cddfSDavid du Colombier ilock(ctlr);
7267dd7cddfSDavid du Colombier regw(ctlr, Isr, 0xFF);
7277dd7cddfSDavid du Colombier regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
7287dd7cddfSDavid du Colombier regw(ctlr, Rcr, r);
729e288d156SDavid du Colombier r = regr(ctlr, Ref2);
7307dd7cddfSDavid du Colombier regw(ctlr, Tcr, LpbkNORMAL);
7317dd7cddfSDavid du Colombier iunlock(ctlr);
7327dd7cddfSDavid du Colombier USED(r);
7337dd7cddfSDavid du Colombier }
7347dd7cddfSDavid du Colombier
7357dd7cddfSDavid du Colombier static void
disable(Dp8390 * ctlr)7367dd7cddfSDavid du Colombier disable(Dp8390* ctlr)
7377dd7cddfSDavid du Colombier {
7387dd7cddfSDavid du Colombier int timo;
7397dd7cddfSDavid du Colombier
7407dd7cddfSDavid du Colombier /*
7417dd7cddfSDavid du Colombier * Stop the chip. Set the Stp bit and wait for the chip
7427dd7cddfSDavid du Colombier * to finish whatever was on its tiny mind before it sets
7437dd7cddfSDavid du Colombier * the Rst bit.
7447dd7cddfSDavid du Colombier * The timeout is needed because there may not be a real
7457dd7cddfSDavid du Colombier * chip there if this is called when probing for a device
7467dd7cddfSDavid du Colombier * at boot.
7477dd7cddfSDavid du Colombier */
7487dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Stp);
7497dd7cddfSDavid du Colombier regw(ctlr, Rbcr0, 0);
7507dd7cddfSDavid du Colombier regw(ctlr, Rbcr1, 0);
7517dd7cddfSDavid du Colombier for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--)
7527dd7cddfSDavid du Colombier ;
7537dd7cddfSDavid du Colombier }
7547dd7cddfSDavid du Colombier
755*ca045b34SDavid du Colombier static void
shutdown(Ether * ether)756*ca045b34SDavid du Colombier shutdown(Ether *ether)
757*ca045b34SDavid du Colombier {
758*ca045b34SDavid du Colombier Dp8390 *ctlr;
759*ca045b34SDavid du Colombier
760*ca045b34SDavid du Colombier ctlr = ether->ctlr;
761*ca045b34SDavid du Colombier disable(ctlr);
762*ca045b34SDavid du Colombier }
763*ca045b34SDavid du Colombier
7647dd7cddfSDavid du Colombier int
dp8390reset(Ether * ether)7657dd7cddfSDavid du Colombier dp8390reset(Ether* ether)
7667dd7cddfSDavid du Colombier {
7677dd7cddfSDavid du Colombier Dp8390 *ctlr;
7687dd7cddfSDavid du Colombier
7697dd7cddfSDavid du Colombier ctlr = ether->ctlr;
7707dd7cddfSDavid du Colombier
7717dd7cddfSDavid du Colombier /*
7727dd7cddfSDavid du Colombier * This is the initialisation procedure described
7737dd7cddfSDavid du Colombier * as 'mandatory' in the datasheet, with references
7747dd7cddfSDavid du Colombier * to the 3C503 technical reference manual.
7757dd7cddfSDavid du Colombier */
7767dd7cddfSDavid du Colombier disable(ctlr);
7777dd7cddfSDavid du Colombier if(ctlr->width != 1)
7787dd7cddfSDavid du Colombier regw(ctlr, Dcr, Ft4WORD|Ls|Wts);
7797dd7cddfSDavid du Colombier else
7807dd7cddfSDavid du Colombier regw(ctlr, Dcr, Ft4WORD|Ls);
7817dd7cddfSDavid du Colombier
7827dd7cddfSDavid du Colombier regw(ctlr, Rbcr0, 0);
7837dd7cddfSDavid du Colombier regw(ctlr, Rbcr1, 0);
7847dd7cddfSDavid du Colombier
7857dd7cddfSDavid du Colombier regw(ctlr, Tcr, LpbkNIC);
7867dd7cddfSDavid du Colombier regw(ctlr, Rcr, Mon);
7877dd7cddfSDavid du Colombier
7887dd7cddfSDavid du Colombier /*
7897dd7cddfSDavid du Colombier * Init the ring hardware and software ring pointers.
7907dd7cddfSDavid du Colombier * Can't initialise ethernet address as it may not be
7917dd7cddfSDavid du Colombier * known yet.
7927dd7cddfSDavid du Colombier */
7937dd7cddfSDavid du Colombier ringinit(ctlr);
7947dd7cddfSDavid du Colombier regw(ctlr, Tpsr, ctlr->tstart);
7957dd7cddfSDavid du Colombier
7967dd7cddfSDavid du Colombier /*
7977dd7cddfSDavid du Colombier * Clear any pending interrupts and mask then all off.
7987dd7cddfSDavid du Colombier */
7997dd7cddfSDavid du Colombier regw(ctlr, Isr, 0xFF);
8007dd7cddfSDavid du Colombier regw(ctlr, Imr, 0);
8017dd7cddfSDavid du Colombier
8027dd7cddfSDavid du Colombier /*
8037dd7cddfSDavid du Colombier * Leave the chip initialised,
8047dd7cddfSDavid du Colombier * but in monitor mode.
8057dd7cddfSDavid du Colombier */
8067dd7cddfSDavid du Colombier regw(ctlr, Cr, Page0|RdABORT|Sta);
8077dd7cddfSDavid du Colombier
8087dd7cddfSDavid du Colombier /*
8097dd7cddfSDavid du Colombier * Set up the software configuration.
8107dd7cddfSDavid du Colombier */
8117dd7cddfSDavid du Colombier ether->attach = attach;
8127dd7cddfSDavid du Colombier ether->transmit = transmit;
8137dd7cddfSDavid du Colombier ether->interrupt = interrupt;
814*ca045b34SDavid du Colombier ether->shutdown = shutdown;
8157dd7cddfSDavid du Colombier ether->ifstat = 0;
8167dd7cddfSDavid du Colombier
8177dd7cddfSDavid du Colombier ether->promiscuous = promiscuous;
8187dd7cddfSDavid du Colombier ether->multicast = multicast;
8197dd7cddfSDavid du Colombier ether->arg = ether;
8207dd7cddfSDavid du Colombier
8217dd7cddfSDavid du Colombier return 0;
822219b2ee8SDavid du Colombier }
823