123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822 |
- /*
- * National Semiconductor DP8390 and clone
- * Network Interface Controller.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "../port/error.h"
- #include "../port/netif.h"
- #include "etherif.h"
- #include "ether8390.h"
- enum { /* NIC core registers */
- Cr = 0x00, /* command register, all pages */
- /* Page 0, read */
- Clda0 = 0x01, /* current local DMA address 0 */
- Clda1 = 0x02, /* current local DMA address 1 */
- Bnry = 0x03, /* boundary pointer (R/W) */
- Tsr = 0x04, /* transmit status register */
- Ncr = 0x05, /* number of collisions register */
- Fifo = 0x06, /* FIFO */
- Isr = 0x07, /* interrupt status register (R/W) */
- Crda0 = 0x08, /* current remote DMA address 0 */
- Crda1 = 0x09, /* current remote DMA address 1 */
- Rsr = 0x0C, /* receive status register */
- Ref0 = 0x0D, /* frame alignment errors */
- Ref1 = 0x0E, /* CRC errors */
- Ref2 = 0x0F, /* missed packet errors */
- /* Page 0, write */
- Pstart = 0x01, /* page start register */
- Pstop = 0x02, /* page stop register */
- Tpsr = 0x04, /* transmit page start address */
- Tbcr0 = 0x05, /* transmit byte count register 0 */
- Tbcr1 = 0x06, /* transmit byte count register 1 */
- Rsar0 = 0x08, /* remote start address register 0 */
- Rsar1 = 0x09, /* remote start address register 1 */
- Rbcr0 = 0x0A, /* remote byte count register 0 */
- Rbcr1 = 0x0B, /* remote byte count register 1 */
- Rcr = 0x0C, /* receive configuration register */
- Tcr = 0x0D, /* transmit configuration register */
- Dcr = 0x0E, /* data configuration register */
- Imr = 0x0F, /* interrupt mask */
- /* Page 1, read/write */
- Par0 = 0x01, /* physical address register 0 */
- Curr = 0x07, /* current page register */
- Mar0 = 0x08, /* multicast address register 0 */
- };
- enum { /* Cr */
- Stp = 0x01, /* stop */
- Sta = 0x02, /* start */
- Txp = 0x04, /* transmit packet */
- Rd0 = 0x08, /* remote DMA command */
- Rd1 = 0x10,
- Rd2 = 0x20,
- RdREAD = Rd0, /* remote read */
- RdWRITE = Rd1, /* remote write */
- RdSEND = Rd1|Rd0, /* send packet */
- RdABORT = Rd2, /* abort/complete remote DMA */
- Ps0 = 0x40, /* page select */
- Ps1 = 0x80,
- Page0 = 0x00,
- Page1 = Ps0,
- Page2 = Ps1,
- };
- enum { /* Isr/Imr */
- Prx = 0x01, /* packet received */
- Ptx = 0x02, /* packet transmitted */
- Rxe = 0x04, /* receive error */
- Txe = 0x08, /* transmit error */
- Ovw = 0x10, /* overwrite warning */
- Cnt = 0x20, /* counter overflow */
- Rdc = 0x40, /* remote DMA complete */
- Rst = 0x80, /* reset status */
- };
- enum { /* Dcr */
- Wts = 0x01, /* word transfer select */
- Bos = 0x02, /* byte order select */
- Las = 0x04, /* long address select */
- Ls = 0x08, /* loopback select */
- Arm = 0x10, /* auto-initialise remote */
- Ft0 = 0x20, /* FIFO threshold select */
- Ft1 = 0x40,
- Ft1WORD = 0x00,
- Ft2WORD = Ft0,
- Ft4WORD = Ft1,
- Ft6WORD = Ft1|Ft0,
- };
- enum { /* Tcr */
- Crc = 0x01, /* inhibit CRC */
- Lb0 = 0x02, /* encoded loopback control */
- Lb1 = 0x04,
- LpbkNORMAL = 0x00, /* normal operation */
- LpbkNIC = Lb0, /* internal NIC module loopback */
- LpbkENDEC = Lb1, /* internal ENDEC module loopback */
- LpbkEXTERNAL = Lb1|Lb0, /* external loopback */
- Atd = 0x08, /* auto transmit disable */
- Ofst = 0x10, /* collision offset enable */
- };
- enum { /* Tsr */
- Ptxok = 0x01, /* packet transmitted */
- Col = 0x04, /* transmit collided */
- Abt = 0x08, /* tranmit aborted */
- Crs = 0x10, /* carrier sense lost */
- Fu = 0x20, /* FIFO underrun */
- Cdh = 0x40, /* CD heartbeat */
- Owc = 0x80, /* out of window collision */
- };
- enum { /* Rcr */
- Sep = 0x01, /* save errored packets */
- Ar = 0x02, /* accept runt packets */
- Ab = 0x04, /* accept broadcast */
- Am = 0x08, /* accept multicast */
- Pro = 0x10, /* promiscuous physical */
- Mon = 0x20, /* monitor mode */
- };
- enum { /* Rsr */
- Prxok = 0x01, /* packet received intact */
- Crce = 0x02, /* CRC error */
- Fae = 0x04, /* frame alignment error */
- Fo = 0x08, /* FIFO overrun */
- Mpa = 0x10, /* missed packet */
- Phy = 0x20, /* physical/multicast address */
- Dis = 0x40, /* receiver disabled */
- Dfr = 0x80, /* deferring */
- };
- typedef struct Hdr Hdr;
- struct Hdr {
- uchar status;
- uchar next;
- uchar len0;
- uchar len1;
- };
- void
- dp8390getea(Ether* ether, uchar* ea)
- {
- Dp8390 *ctlr;
- uchar cr;
- int i;
- ctlr = ether->ctlr;
- /*
- * Get the ethernet address from the chip.
- * Take care to restore the command register
- * afterwards.
- */
- ilock(ctlr);
- cr = regr(ctlr, Cr) & ~Txp;
- regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
- for(i = 0; i < Eaddrlen; i++)
- ea[i] = regr(ctlr, Par0+i);
- regw(ctlr, Cr, cr);
- iunlock(ctlr);
- }
- void
- dp8390setea(Ether* ether)
- {
- int i;
- uchar cr;
- Dp8390 *ctlr;
- ctlr = ether->ctlr;
- /*
- * Set the ethernet address into the chip.
- * Take care to restore the command register
- * afterwards. Don't care about multicast
- * addresses as multicast is never enabled
- * (currently).
- */
- ilock(ctlr);
- cr = regr(ctlr, Cr) & ~Txp;
- regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
- for(i = 0; i < Eaddrlen; i++)
- regw(ctlr, Par0+i, ether->ea[i]);
- regw(ctlr, Cr, cr);
- iunlock(ctlr);
- }
- static void*
- _dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
- {
- uchar cr;
- int timo;
- /*
- * Read some data at offset 'from' in the card's memory
- * using the DP8390 remote DMA facility, and place it at
- * 'to' in main memory, via the I/O data port.
- */
- cr = regr(ctlr, Cr) & ~Txp;
- regw(ctlr, Cr, Page0|RdABORT|Sta);
- regw(ctlr, Isr, Rdc);
- /*
- * Set up the remote DMA address and count.
- */
- len = ROUNDUP(len, ctlr->width);
- regw(ctlr, Rbcr0, len & 0xFF);
- regw(ctlr, Rbcr1, (len>>8) & 0xFF);
- regw(ctlr, Rsar0, from & 0xFF);
- regw(ctlr, Rsar1, (from>>8) & 0xFF);
- /*
- * Start the remote DMA read and suck the data
- * out of the I/O port.
- */
- regw(ctlr, Cr, Page0|RdREAD|Sta);
- rdread(ctlr, to, len);
- /*
- * Wait for the remote DMA to complete. The timeout
- * is necessary because this routine may be called on
- * a non-existent chip during initialisation and, due
- * to the miracles of the bus, it's possible to get this
- * far and still be talking to a slot full of nothing.
- */
- for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
- ;
- regw(ctlr, Isr, Rdc);
- regw(ctlr, Cr, cr);
- return to;
- }
- void*
- dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
- {
- void *v;
- ilock(ctlr);
- v = _dp8390read(ctlr, to, from, len);
- iunlock(ctlr);
- return v;
- }
- static void*
- dp8390write(Dp8390* ctlr, ulong to, void* from, ulong len)
- {
- ulong crda;
- uchar cr;
- int timo, width;
- top:
- /*
- * Write some data to offset 'to' in the card's memory
- * using the DP8390 remote DMA facility, reading it at
- * 'from' in main memory, via the I/O data port.
- */
- cr = regr(ctlr, Cr) & ~Txp;
- regw(ctlr, Cr, Page0|RdABORT|Sta);
- regw(ctlr, Isr, Rdc);
- len = ROUNDUP(len, ctlr->width);
- /*
- * Set up the remote DMA address and count.
- * This is straight from the DP8390[12D] datasheet,
- * hence the initial set up for read.
- * Assumption here that the A7000 EtherV card will
- * never need a dummyrr.
- */
- if(ctlr->dummyrr && (ctlr->width == 1 || ctlr->width == 2)){
- if(ctlr->width == 2)
- width = 1;
- else
- width = 0;
- crda = to-1-width;
- regw(ctlr, Rbcr0, (len+1+width) & 0xFF);
- regw(ctlr, Rbcr1, ((len+1+width)>>8) & 0xFF);
- regw(ctlr, Rsar0, crda & 0xFF);
- regw(ctlr, Rsar1, (crda>>8) & 0xFF);
- regw(ctlr, Cr, Page0|RdREAD|Sta);
-
- for(timo=0;; timo++){
- if(timo > 10000){
- print("ether8390: dummyrr timeout; assuming nodummyrr\n");
- ctlr->dummyrr = 0;
- goto top;
- }
- crda = regr(ctlr, Crda0);
- crda |= regr(ctlr, Crda1)<<8;
- if(crda == to){
- /*
- * Start the remote DMA write and make sure
- * the registers are correct.
- */
- regw(ctlr, Cr, Page0|RdWRITE|Sta);
-
- crda = regr(ctlr, Crda0);
- crda |= regr(ctlr, Crda1)<<8;
- if(crda != to)
- panic("crda write %lud to %lud\n", crda, to);
-
- break;
- }
- }
- }
- else{
- regw(ctlr, Rsar0, to & 0xFF);
- regw(ctlr, Rsar1, (to>>8) & 0xFF);
- regw(ctlr, Rbcr0, len & 0xFF);
- regw(ctlr, Rbcr1, (len>>8) & 0xFF);
- regw(ctlr, Cr, Page0|RdWRITE|Sta);
- }
- /*
- * Pump the data into the I/O port
- * then wait for the remote DMA to finish.
- */
- rdwrite(ctlr, from, len);
- for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
- ;
- regw(ctlr, Isr, Rdc);
- regw(ctlr, Cr, cr);
- return (void*)to;
- }
- static void
- ringinit(Dp8390* ctlr)
- {
- regw(ctlr, Pstart, ctlr->pstart);
- regw(ctlr, Pstop, ctlr->pstop);
- regw(ctlr, Bnry, ctlr->pstop-1);
- regw(ctlr, Cr, Page1|RdABORT|Stp);
- regw(ctlr, Curr, ctlr->pstart);
- regw(ctlr, Cr, Page0|RdABORT|Stp);
- ctlr->nxtpkt = ctlr->pstart;
- }
- static uchar
- getcurr(Dp8390* ctlr)
- {
- uchar cr, curr;
- cr = regr(ctlr, Cr) & ~Txp;
- regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
- curr = regr(ctlr, Curr);
- regw(ctlr, Cr, cr);
- return curr;
- }
- static void
- receive(Ether* ether)
- {
- Dp8390 *ctlr;
- uchar curr, *p;
- Hdr hdr;
- ulong count, data, len;
- Block *bp;
- ctlr = ether->ctlr;
- for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){
- data = ctlr->nxtpkt*Dp8390BufSz;
- if(ctlr->ram)
- memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr));
- else
- _dp8390read(ctlr, &hdr, data, sizeof(Hdr));
- /*
- * Don't believe the upper byte count, work it
- * out from the software next-page pointer and
- * the current next-page pointer.
- */
- if(hdr.next > ctlr->nxtpkt)
- len = hdr.next - ctlr->nxtpkt - 1;
- else
- len = (ctlr->pstop-ctlr->nxtpkt) + (hdr.next-ctlr->pstart) - 1;
- if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
- len--;
- len = ((len<<8)|hdr.len0)-4;
- /*
- * Chip is badly scrogged, reinitialise the ring.
- */
- if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop
- || len < 60 || len > sizeof(Etherpkt)){
- print("dp8390: H%2.2ux+%2.2ux+%2.2ux+%2.2ux,%lud\n",
- hdr.status, hdr.next, hdr.len0, hdr.len1, len);
- regw(ctlr, Cr, Page0|RdABORT|Stp);
- ringinit(ctlr);
- regw(ctlr, Cr, Page0|RdABORT|Sta);
- return;
- }
- /*
- * If it's a good packet read it in to the software buffer.
- * If the packet wraps round the hardware ring, read it in
- * two pieces.
- */
- if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && (bp = iallocb(len))){
- p = bp->rp;
- bp->wp = p+len;
- data += sizeof(Hdr);
- if((data+len) >= ctlr->pstop*Dp8390BufSz){
- count = ctlr->pstop*Dp8390BufSz - data;
- if(ctlr->ram)
- memmove(p, (void*)(ether->mem+data), count);
- else
- _dp8390read(ctlr, p, data, count);
- p += count;
- data = ctlr->pstart*Dp8390BufSz;
- len -= count;
- }
- if(len){
- if(ctlr->ram)
- memmove(p, (void*)(ether->mem+data), len);
- else
- _dp8390read(ctlr, p, data, len);
- }
- /*
- * Copy the packet to whoever wants it.
- */
- etheriq(ether, bp, 1);
- }
- /*
- * Finished with this packet, update the
- * hardware and software ring pointers.
- */
- ctlr->nxtpkt = hdr.next;
- hdr.next--;
- if(hdr.next < ctlr->pstart)
- hdr.next = ctlr->pstop-1;
- regw(ctlr, Bnry, hdr.next);
- }
- }
- static void
- txstart(Ether* ether)
- {
- int len;
- Dp8390 *ctlr;
- Block *bp;
- uchar minpkt[ETHERMINTU], *rp;
- ctlr = ether->ctlr;
- /*
- * This routine is called both from the top level and from interrupt
- * level and expects to be called with ctlr already locked.
- */
- if(ctlr->txbusy)
- return;
- bp = qget(ether->oq);
- if(bp == nil)
- return;
- /*
- * Make sure the packet is of minimum length;
- * copy it to the card's memory by the appropriate means;
- * start the transmission.
- */
- len = BLEN(bp);
- rp = bp->rp;
- if(len < ETHERMINTU){
- rp = minpkt;
- memmove(rp, bp->rp, len);
- memset(rp+len, 0, ETHERMINTU-len);
- len = ETHERMINTU;
- }
- if(ctlr->ram)
- memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len);
- else
- dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len);
- freeb(bp);
- regw(ctlr, Tbcr0, len & 0xFF);
- regw(ctlr, Tbcr1, (len>>8) & 0xFF);
- regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
- ether->outpackets++;
- ctlr->txbusy = 1;
- }
- static void
- transmit(Ether* ether)
- {
- Dp8390 *ctlr;
- ctlr = ether->ctlr;
- ilock(ctlr);
- txstart(ether);
- iunlock(ctlr);
- }
- static void
- overflow(Ether *ether)
- {
- Dp8390 *ctlr;
- uchar txp;
- int resend;
- ctlr = ether->ctlr;
- /*
- * The following procedure is taken from the DP8390[12D] datasheet,
- * it seems pretty adamant that this is what has to be done.
- */
- txp = regr(ctlr, Cr) & Txp;
- regw(ctlr, Cr, Page0|RdABORT|Stp);
- delay(2);
- regw(ctlr, Rbcr0, 0);
- regw(ctlr, Rbcr1, 0);
- resend = 0;
- if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0)
- resend = 1;
- regw(ctlr, Tcr, LpbkNIC);
- regw(ctlr, Cr, Page0|RdABORT|Sta);
- receive(ether);
- regw(ctlr, Isr, Ovw);
- regw(ctlr, Tcr, LpbkNORMAL);
- if(resend)
- regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
- }
- static void
- interrupt(Ureg*, void* arg)
- {
- Ether *ether;
- Dp8390 *ctlr;
- uchar isr, r;
- ether = arg;
- ctlr = ether->ctlr;
- /*
- * While there is something of interest,
- * clear all the interrupts and process.
- */
- ilock(ctlr);
- regw(ctlr, Imr, 0x00);
- while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){
- if(isr & Ovw){
- overflow(ether);
- regw(ctlr, Isr, Ovw);
- ether->overflows++;
- }
- /*
- * Packets have been received.
- * Take a spin round the ring.
- */
- if(isr & (Rxe|Prx)){
- receive(ether);
- regw(ctlr, Isr, Rxe|Prx);
- }
- /*
- * A packet completed transmission, successfully or
- * not. Start transmission on the next buffered packet,
- * and wake the output routine.
- */
- if(isr & (Txe|Ptx)){
- r = regr(ctlr, Tsr);
- if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){
- print("dp8390: Tsr %#2.2ux", r);
- ether->oerrs++;
- }
- regw(ctlr, Isr, Txe|Ptx);
- if(isr & Ptx)
- ether->outpackets++;
- ctlr->txbusy = 0;
- txstart(ether);
- }
- if(isr & Cnt){
- ether->frames += regr(ctlr, Ref0);
- ether->crcs += regr(ctlr, Ref1);
- ether->buffs += regr(ctlr, Ref2);
- regw(ctlr, Isr, Cnt);
- }
- }
- regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
- iunlock(ctlr);
- }
- static uchar allmar[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- static void
- setfilter(Ether *ether, Dp8390 *ctlr)
- {
- uchar r, cr;
- int i;
- uchar *mar;
- r = Ab;
- mar = 0;
- if(ether->prom){
- r |= Pro|Am;
- mar = allmar;
- } else if(ether->nmaddr){
- r |= Am;
- mar = ctlr->mar;
- }
- if(mar){
- cr = regr(ctlr, Cr) & ~Txp;
- regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
- for(i = 0; i < 8; i++)
- regw(ctlr, Mar0+i, *(mar++));
- regw(ctlr, Cr, cr);
- }
- regw(ctlr, Rcr, r);
- }
- static void
- promiscuous(void *arg, int )
- {
- Ether *ether;
- Dp8390 *ctlr;
- ether = arg;
- ctlr = ether->ctlr;
- ilock(ctlr);
- setfilter(ether, ctlr);
- iunlock(ctlr);
- }
- static void
- setbit(Dp8390 *ctlr, int bit, int on)
- {
- int i, h;
- i = bit/8;
- h = bit%8;
- if(on){
- if(++(ctlr->mref[bit]) == 1)
- ctlr->mar[i] |= 1<<h;
- } else {
- if(--(ctlr->mref[bit]) <= 0){
- ctlr->mref[bit] = 0;
- ctlr->mar[i] &= ~(1<<h);
- }
- }
- }
- static uchar reverse[64];
- static void
- multicast(void* arg, uchar *addr, int on)
- {
- Ether *ether;
- Dp8390 *ctlr;
- int i;
- ulong h;
- ether = arg;
- ctlr = ether->ctlr;
- if(reverse[1] == 0){
- for(i = 0; i < 64; i++)
- reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1)
- | ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5);
- }
- /*
- * change filter bits
- */
- h = ethercrc(addr, 6);
- ilock(ctlr);
- setbit(ctlr, reverse[h&0x3f], on);
- setfilter(ether, ctlr);
- iunlock(ctlr);
- }
- static void
- attach(Ether* ether)
- {
- Dp8390 *ctlr;
- uchar r;
- ctlr = ether->ctlr;
- /*
- * Enable the chip for transmit/receive.
- * The init routine leaves the chip in monitor
- * mode. Clear the missed-packet counter, it
- * increments while in monitor mode.
- * Sometimes there's an interrupt pending at this
- * point but there's nothing in the Isr, so
- * any pending interrupts are cleared and the
- * mask of acceptable interrupts is enabled here.
- */
- r = Ab;
- if(ether->prom)
- r |= Pro;
- if(ether->nmaddr)
- r |= Am;
- ilock(ctlr);
- regw(ctlr, Isr, 0xFF);
- regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
- regw(ctlr, Rcr, r);
- r = regr(ctlr, Ref2);
- regw(ctlr, Tcr, LpbkNORMAL);
- iunlock(ctlr);
- USED(r);
- }
- static void
- disable(Dp8390* ctlr)
- {
- int timo;
- /*
- * Stop the chip. Set the Stp bit and wait for the chip
- * to finish whatever was on its tiny mind before it sets
- * the Rst bit.
- * The timeout is needed because there may not be a real
- * chip there if this is called when probing for a device
- * at boot.
- */
- regw(ctlr, Cr, Page0|RdABORT|Stp);
- regw(ctlr, Rbcr0, 0);
- regw(ctlr, Rbcr1, 0);
- for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--)
- ;
- }
- static void
- shutdown(Ether *ether)
- {
- Dp8390 *ctlr;
- ctlr = ether->ctlr;
- disable(ctlr);
- }
- int
- dp8390reset(Ether* ether)
- {
- Dp8390 *ctlr;
- ctlr = ether->ctlr;
- /*
- * This is the initialisation procedure described
- * as 'mandatory' in the datasheet, with references
- * to the 3C503 technical reference manual.
- */
- disable(ctlr);
- if(ctlr->width != 1)
- regw(ctlr, Dcr, Ft4WORD|Ls|Wts);
- else
- regw(ctlr, Dcr, Ft4WORD|Ls);
- regw(ctlr, Rbcr0, 0);
- regw(ctlr, Rbcr1, 0);
- regw(ctlr, Tcr, LpbkNIC);
- regw(ctlr, Rcr, Mon);
- /*
- * Init the ring hardware and software ring pointers.
- * Can't initialise ethernet address as it may not be
- * known yet.
- */
- ringinit(ctlr);
- regw(ctlr, Tpsr, ctlr->tstart);
- /*
- * Clear any pending interrupts and mask then all off.
- */
- regw(ctlr, Isr, 0xFF);
- regw(ctlr, Imr, 0);
- /*
- * Leave the chip initialised,
- * but in monitor mode.
- */
- regw(ctlr, Cr, Page0|RdABORT|Sta);
- /*
- * Set up the software configuration.
- */
- ether->attach = attach;
- ether->transmit = transmit;
- ether->interrupt = interrupt;
- ether->shutdown = shutdown;
- ether->ifstat = 0;
- ether->promiscuous = promiscuous;
- ether->multicast = multicast;
- ether->arg = ether;
- return 0;
- }
|