static void rtl8139halt(Ctlr* ctlr) { csr8w(ctlr, Cr, 0); csr16w(ctlr, Imr, 0); csr16w(ctlr, Isr, ~0); }
static void rtl8139init(Ether* edev) { int i; uint32_t r; Ctlr *ctlr; uint8_t *alloc; ctlr = edev->ctlr; ilock(&ctlr->ilock); rtl8139halt(ctlr); /* * MAC Address. */ r = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0]; csr32w(ctlr, Idr0, r); r = (edev->ea[5]<<8)|edev->ea[4]; csr32w(ctlr, Idr0+4, r); /* * Receiver */ alloc = (uint8_t*)ROUNDUP((uint32_t)ctlr->alloc, 32); ctlr->rbstart = alloc; alloc += ctlr->rblen+16; memset(ctlr->rbstart, 0, ctlr->rblen+16); csr32w(ctlr, Rbstart, PADDR(ctlr->rbstart)); ctlr->rcr = Rxfth256|Rblen|Mrxdmaunlimited|Ab|Apm; /* * Transmitter. */ for(i = 0; i < Ntd; i++){ ctlr->td[i].tsd = Tsd0+i*4; ctlr->td[i].tsad = Tsad0+i*4; ctlr->td[i].data = alloc; alloc += Tdbsz; } ctlr->ntd = ctlr->tdh = ctlr->tdi = 0; ctlr->etxth = 128/32; /* * Interrupts. */ csr32w(ctlr, TimerInt, 0); csr16w(ctlr, Imr, Serr|Timer|Fovw|PunLc|Rxovw|Ter|Tok|Rer|Rok); csr32w(ctlr, Mpc, 0); /* * Enable receiver/transmitter. * Need to enable before writing the Rcr or it won't take. */ csr8w(ctlr, Cr, Te|Re); csr32w(ctlr, Tcr, Mtxdma2048); csr32w(ctlr, Rcr, ctlr->rcr); iunlock(&ctlr->ilock); }
static void vt6102lproc(void* arg) { Ctlr *ctlr; Ether *edev; MiiPhy *phy; edev = arg; ctlr = edev->ctlr; while(waserror()) ; for(;;){ if(ctlr->mii == nil || ctlr->mii->curphy == nil) break; if(miistatus(ctlr->mii) < 0) goto enable; phy = ctlr->mii->curphy; ilock(&ctlr->clock); if(phy->fd) ctlr->cr |= Fdx; else ctlr->cr &= ~Fdx; csr16w(ctlr, Cr, ctlr->cr); iunlock(&ctlr->clock); enable: ctlr->lwakeup = 0; vt6102imr(ctlr, Srci); ctlr->lsleep++; sleep(&ctlr->lrendez, vt6102wakeup, &ctlr->lwakeup); } pexit("vt6102lproc: done", 1); }
static void vt6102imr(Ctlr* ctlr, int imr) { ilock(&ctlr->clock); ctlr->imr |= imr; csr16w(ctlr, Imr, ctlr->imr); iunlock(&ctlr->clock); }
static void vt6102transmit(Ether* edev) { Block *bp; Ctlr *ctlr; Ds *ds, *next; int control, i, o, prefix, size, tdused, timeo; ctlr = edev->ctlr; ilock(&ctlr->tlock); /* * Free any completed packets */ ds = ctlr->tdh; for(tdused = ctlr->tdused; tdused > 0; tdused--){ /* * For some errors the chip will turn the Tx engine * off. Wait for that to happen. * Could reset and re-init the chip here if it doesn't * play fair. * To do: adjust Tx FIFO threshold on underflow. */ if(ds->status & (Abt|Tbuff|Udf)){ for(timeo = 0; timeo < 1000; timeo++){ if(!(csr16r(ctlr, Cr) & Txon)) break; microdelay(1); } ds->status = Own; csr32w(ctlr, Txdaddr, PCIWADDR(ds)); } if(ds->status & Own) break; ds->addr = 0; ds->branch = 0; if(ds->bp != nil){ freeb(ds->bp); ds->bp = nil; } for(i = 0; i < Ntxstats-1; i++){ if(ds->status & (1<<i)) ctlr->txstats[i]++; } ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT; ds = ds->next; } ctlr->tdh = ds; /* * Try to fill the ring back up. */ ds = ctlr->tdt; while(tdused < ctlr->ntd-2){ if((bp = qget(edev->oq)) == nil) break; tdused++; size = BLEN(bp); prefix = 0; if(o = (((int)bp->rp) & 0x03)){ prefix = Txcopy-o; if(prefix > size) prefix = size; memmove(ds->bounce, bp->rp, prefix); ds->addr = PCIWADDR(ds->bounce); bp->rp += prefix; size -= prefix; } next = ds->next; ds->branch = PCIWADDR(ds->next); if(size){ if(prefix){ next->bp = bp; next->addr = PCIWADDR(bp->rp); next->branch = PCIWADDR(next->next); next->control = Edp|Chain|((size<<TbsSHIFT) & TbsMASK); control = Stp|Chain|((prefix<<TbsSHIFT) & TbsMASK); next = next->next; tdused++; ctlr->tsplit++; } else{ ds->bp = bp; ds->addr = PCIWADDR(bp->rp); control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK); ctlr->taligned++; } } else{ freeb(bp); control = Edp|Stp|((prefix<<TbsSHIFT) & TbsMASK); ctlr->tcopied++; } ds->control = control; if(tdused >= ctlr->ntd-2){ ds->control |= Ic; ctlr->txdw++; } coherence(); ds->status = Own; ds = next; } ctlr->tdt = ds; ctlr->tdused = tdused; if(ctlr->tdused) csr16w(ctlr, Cr, Tdmd|ctlr->cr); iunlock(&ctlr->tlock); }
static void vt6102attach(Ether* edev) { int dsz, i; Ctlr *ctlr; Ds *ds, *prev; uchar *alloc, *bounce; char name[KNAMELEN]; ctlr = edev->ctlr; qlock(&ctlr->alock); if(ctlr->alloc != nil){ qunlock(&ctlr->alock); return; } /* * Descriptor and bounce-buffer space. * Must all be aligned on a 4-byte boundary, * but try to align on cache-lines. */ ctlr->nrd = Nrd; ctlr->ntd = Ntd; dsz = ROUNDUP(sizeof(Ds), ctlr->cls); alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz + ctlr->ntd*Txcopy, dsz, 0, 0); if(alloc == nil){ qunlock(&ctlr->alock); error(Enomem); } ctlr->alloc = alloc; ctlr->rd = (Ds*)alloc; if(waserror()){ ds = ctlr->rd; for(i = 0; i < ctlr->nrd; i++){ if(ds->bp != nil){ freeb(ds->bp); ds->bp = nil; } if((ds = ds->next) == nil) break; } free(ctlr->alloc); ctlr->alloc = nil; qunlock(&ctlr->alock); nexterror(); } prev = ctlr->rd + ctlr->nrd-1; for(i = 0; i < ctlr->nrd; i++){ ds = (Ds*)alloc; alloc += dsz; ds->control = Rdbsz; ds->branch = PCIWADDR(alloc); ds->bp = iallocb(Rdbsz+3); if(ds->bp == nil) error("vt6102: can't allocate receive ring\n"); ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4); ds->addr = PCIWADDR(ds->bp->rp); ds->next = (Ds*)alloc; ds->prev = prev; prev = ds; ds->status = Own; } prev->branch = 0; prev->next = ctlr->rd; prev->status = 0; ctlr->rdh = ctlr->rd; ctlr->td = (Ds*)alloc; prev = ctlr->td + ctlr->ntd-1; bounce = alloc + ctlr->ntd*dsz; for(i = 0; i < ctlr->ntd; i++){ ds = (Ds*)alloc; alloc += dsz; ds->bounce = bounce; bounce += Txcopy; ds->next = (Ds*)alloc; ds->prev = prev; prev = ds; } prev->next = ctlr->td; ctlr->tdh = ctlr->tdt = ctlr->td; ctlr->tdused = 0; ctlr->cr = Dpoll|Rdmd|Txon|Rxon|Strt; /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/ ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx; ilock(&ctlr->clock); csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd)); csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td)); csr16w(ctlr, Isr, ~0); csr16w(ctlr, Imr, ctlr->imr); csr16w(ctlr, Cr, ctlr->cr); iunlock(&ctlr->clock); snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno); kproc(name, vt6102lproc, edev); qunlock(&ctlr->alock); poperror(); }