📄 etherdp83820.c
字号:
iprint("10Mb/s\n"); break; case Spdsts100: /* 1Gbps */ ctlr->cfg |= Mode1000; iprint("1Gb/s\n"); break; } csr32w(ctlr, Cfg, ctlr->cfg);}static voiddp83820init(Ether* edev){ int i; Ctlr *ctlr; Desc *desc; uchar *alloc; ctlr = edev->ctlr; dp83820halt(ctlr); /* * Receiver */ alloc = (uchar*)ROUNDUP((ulong)ctlr->alloc, 8); ctlr->rd = (Desc*)alloc; alloc += ctlr->nrd*sizeof(Desc); memset(ctlr->rd, 0, ctlr->nrd*sizeof(Desc)); ctlr->rdx = 0; for(i = 0; i < ctlr->nrd; i++){ desc = &ctlr->rd[i]; desc->link = PCIWADDR(&ctlr->rd[NEXT(i, ctlr->nrd)]); if(dp83820rballoc(desc) == nil) continue; } csr32w(ctlr, Rxdphi, 0); csr32w(ctlr, Rxdp, PCIWADDR(ctlr->rd)); for(i = 0; i < Eaddrlen; i += 2){ csr32w(ctlr, Rfcr, i); csr32w(ctlr, Rfdr, (edev->ea[i+1]<<8)|edev->ea[i]); } csr32w(ctlr, Rfcr, Rfen|Aab|Aam|Apm); ctlr->rxcfg = Stripcrc|(((2*(ETHERMINTU+4))/8)<<RxdrthSHFT); ctlr->imr |= Rxorn|Rxidle|Rxearly|Rxdesc|Rxok; /* * Transmitter. */ ctlr->td = (Desc*)alloc; memset(ctlr->td, 0, ctlr->ntd*sizeof(Desc)); ctlr->tdh = ctlr->tdt = ctlr->ntq = 0; for(i = 0; i < ctlr->ntd; i++){ desc = &ctlr->td[i]; desc->link = PCIWADDR(&ctlr->td[NEXT(i, ctlr->ntd)]); } csr32w(ctlr, Txdphi, 0); csr32w(ctlr, Txdp, PCIWADDR(ctlr->td)); ctlr->txcfg = Atp|(((2*(ETHERMINTU+4))/32)<<FlthSHFT)|((4096/32)<<TxdrthSHFT); ctlr->imr |= Txurn|Txidle|Txdesc|Txok; ilock(&ctlr->ilock); dp83820cfg(ctlr); csr32w(ctlr, Mibc, Aclr); ctlr->imr |= Mib; csr32w(ctlr, Imr, ctlr->imr); /* try coalescing adjacent interrupts; use hold-off interval of 100µs */ csr32w(ctlr, Ihr, Ihctl|(1<<IhSHFT)); csr32w(ctlr, Ier, Ien); csr32w(ctlr, Cr, Rxe|Txe); iunlock(&ctlr->ilock);}static voiddp83820attach(Ether* edev){ Block *bp; Ctlr *ctlr; ctlr = edev->ctlr; qlock(&ctlr->alock); if(ctlr->alloc != nil){ qunlock(&ctlr->alock); return; } if(waserror()){ if(ctlr->mii != nil){ free(ctlr->mii); ctlr->mii = nil; } if(ctlr->alloc != nil){ free(ctlr->alloc); ctlr->alloc = nil; } qunlock(&ctlr->alock); nexterror(); } if(!(ctlr->cfg & Tbien)){ if((ctlr->mii = malloc(sizeof(Mii))) == nil) error(Enomem); ctlr->mii->ctlr = ctlr; ctlr->mii->mir = dp83820miimir; ctlr->mii->miw = dp83820miimiw; if(mii(ctlr->mii, ~0) == 0) error("no PHY"); ctlr->cfg |= Dupstsien|Lnkstsien|Spdstsien; ctlr->imr |= Phy; } ctlr->nrd = Nrd; ctlr->nrb = Nrb; ctlr->ntd = Ntd; ctlr->alloc = mallocz((ctlr->nrd+ctlr->ntd)*sizeof(Desc) + 7, 0); if(ctlr->alloc == nil) error(Enomem); for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){ if((bp = allocb(Rbsz)) == nil) break; bp->free = dp83820rbfree; dp83820rbfree(bp); } dp83820init(edev); qunlock(&ctlr->alock); poperror();}static voiddp83820transmit(Ether* edev){ Block *bp; Ctlr *ctlr; Desc *desc; int cmdsts, r, x; ctlr = edev->ctlr; ilock(&ctlr->tlock); bp = nil; for(x = ctlr->tdh; ctlr->ntq; x = NEXT(x, ctlr->ntd)){ desc = &ctlr->td[x]; if((cmdsts = desc->cmdsts) & Own) break; if(!(cmdsts & Ok)){ if(cmdsts & Ec) ctlr->ec++; if(cmdsts & Owc) ctlr->owc++; if(cmdsts & Ed) ctlr->ed++; if(cmdsts & Crs) ctlr->crs++; if(cmdsts & Tfu) ctlr->tfu++; if(cmdsts & Txa) ctlr->txa++; edev->oerrs++; } desc->bp->next = bp; bp = desc->bp; desc->bp = nil; ctlr->ntq--; } ctlr->tdh = x; if(bp != nil) freeblist(bp); x = ctlr->tdt; while(ctlr->ntq < (ctlr->ntd-1)){ if((bp = qget(edev->oq)) == nil) break; desc = &ctlr->td[x]; desc->bufptr = PCIWADDR(bp->rp); desc->bp = bp; ctlr->ntq++; coherence(); desc->cmdsts = Own|Intr|BLEN(bp); x = NEXT(x, ctlr->ntd); } if(x != ctlr->tdt){ ctlr->tdt = x; r = csr32r(ctlr, Cr); csr32w(ctlr, Cr, Txe|r); } iunlock(&ctlr->tlock);}static voiddp83820interrupt(Ureg*, void* arg){ Block *bp; Ctlr *ctlr; Desc *desc; Ether *edev; int cmdsts, i, isr, r, x; edev = arg; ctlr = edev->ctlr; for(isr = csr32r(ctlr, Isr); isr & ctlr->imr; isr = csr32r(ctlr, Isr)){ if(isr & (Rxorn|Rxidle|Rxearly|Rxerr|Rxdesc|Rxok)){ x = ctlr->rdx; desc = &ctlr->rd[x]; while((cmdsts = desc->cmdsts) & Own){ if((cmdsts & Ok) && desc->bp != nil){ bp = desc->bp; desc->bp = nil; bp->wp += cmdsts & SizeMASK; etheriq(edev, bp, 1); } //else if(!(cmdsts & Ok)){ // iprint("dp83820: rx %8.8uX:", cmdsts); // bp = desc->bp; // for(i = 0; i < 20; i++) // iprint(" %2.2uX", bp->rp[i]); // iprint("\n"); //} dp83820rballoc(desc); x = NEXT(x, ctlr->nrd); desc = &ctlr->rd[x]; } ctlr->rdx = x; if(isr & Rxidle){ r = csr32r(ctlr, Cr); csr32w(ctlr, Cr, Rxe|r); ctlr->rxidle++; } isr &= ~(Rxorn|Rxidle|Rxearly|Rxerr|Rxdesc|Rxok); } if(isr & Txurn){ x = (ctlr->txcfg & TxdrthMASK)>>TxdrthSHFT; r = (ctlr->txcfg & FlthMASK)>>FlthSHFT; if(x < ((TxdrthMASK)>>TxdrthSHFT) && x < (2048/32 - r)){ ctlr->txcfg &= ~TxdrthMASK; x++; ctlr->txcfg |= x<<TxdrthSHFT; csr32w(ctlr, Txcfg, ctlr->txcfg); } } if(isr & (Txurn|Txidle|Txdesc|Txok)){ dp83820transmit(edev); isr &= ~(Txurn|Txidle|Txdesc|Txok); } if(isr & Mib){ for(i = 0; i < Nmibd; i++){ r = csr32r(ctlr, Mibd+(i*sizeof(int))); ctlr->mibd[i] += r & 0xFFFF; } isr &= ~Mib; } if((isr & Phy) && ctlr->mii != nil){ ctlr->mii->mir(ctlr->mii, 1, Bmsr); print("phy: cfg %8.8uX bmsr %4.4uX\n", csr32r(ctlr, Cfg), ctlr->mii->mir(ctlr->mii, 1, Bmsr)); dp83820cfg(ctlr); isr &= ~Phy; } if(isr) iprint("dp83820: isr %8.8uX\n", isr); }}static longdp83820ifstat(Ether* edev, void* a, long n, ulong offset){ char *p; Ctlr *ctlr; int i, l, r; ctlr = edev->ctlr; edev->crcs = ctlr->mibd[Mibd+(1*sizeof(int))]; edev->frames = ctlr->mibd[Mibd+(3*sizeof(int))]; edev->buffs = ctlr->mibd[Mibd+(5*sizeof(int))]; edev->overflows = ctlr->mibd[Mibd+(2*sizeof(int))]; if(n == 0) return 0; p = malloc(READSTR); l = 0; for(i = 0; i < Nmibd; i++){ r = csr32r(ctlr, Mibd+(i*sizeof(int))); ctlr->mibd[i] += r & 0xFFFF; if(ctlr->mibd[i] != 0 && dp83820mibs[i] != nil) l += snprint(p+l, READSTR-l, "%s: %ud %ud\n", dp83820mibs[i], ctlr->mibd[i], r); } l += snprint(p+l, READSTR-l, "rxidle %d\n", ctlr->rxidle); l += snprint(p+l, READSTR-l, "ec %d\n", ctlr->ec); l += snprint(p+l, READSTR-l, "owc %d\n", ctlr->owc); l += snprint(p+l, READSTR-l, "ed %d\n", ctlr->ed); l += snprint(p+l, READSTR-l, "crs %d\n", ctlr->crs); l += snprint(p+l, READSTR-l, "tfu %d\n", ctlr->tfu); l += snprint(p+l, READSTR-l, "txa %d\n", ctlr->txa); l += snprint(p+l, READSTR, "rom:"); for(i = 0; i < 0x10; i++){ if(i && ((i & 0x07) == 0)) l += snprint(p+l, READSTR-l, "\n "); l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->eeprom[i]); } l += snprint(p+l, READSTR-l, "\n"); if(ctlr->mii != nil && ctlr->mii->curphy != nil){ l += snprint(p+l, READSTR, "phy:"); for(i = 0; i < NMiiPhyr; i++){ if(i && ((i & 0x07) == 0)) l += snprint(p+l, READSTR-l, "\n "); r = miimir(ctlr->mii, i); l += snprint(p+l, READSTR-l, " %4.4uX", r); } snprint(p+l, READSTR-l, "\n"); } n = readstr(offset, a, n, p); free(p); return n;}static voiddp83820promiscuous(void* arg, int on){ USED(arg, on);}/* multicast already on, don't need to do anything */static voiddp83820multicast(void*, uchar*, int){}static intatc93c46r(Ctlr* ctlr, int address){ int data, i, mear, r, size; /* * Analog Technology, Inc. ATC93C46 * or equivalent serial EEPROM. */ mear = csr32r(ctlr, Mear); mear &= ~(Eesel|Eeclk|Eedo|Eedi); r = Eesel|mear;reread: csr32w(ctlr, Mear, r); data = 0x06; for(i = 3-1; i >= 0; i--){ if(data & (1<<i)) r |= Eedi; else r &= ~Eedi; csr32w(ctlr, Mear, r); csr32w(ctlr, Mear, Eeclk|r); microdelay(1); csr32w(ctlr, Mear, r); microdelay(1); } /* * First time through must work out the EEPROM size. */ if((size = ctlr->eepromsz) == 0) size = 8; for(size = size-1; size >= 0; size--){ if(address & (1<<size)) r |= Eedi; else r &= ~Eedi; csr32w(ctlr, Mear, r); microdelay(1); csr32w(ctlr, Mear, Eeclk|r); microdelay(1); csr32w(ctlr, Mear, r); microdelay(1); if(!(csr32r(ctlr, Mear) & Eedo)) break; } r &= ~Eedi; data = 0; for(i = 16-1; i >= 0; i--){ csr32w(ctlr, Mear, Eeclk|r); microdelay(1); if(csr32r(ctlr, Mear) & Eedo) data |= (1<<i); csr32w(ctlr, Mear, r); microdelay(1); } csr32w(ctlr, Mear, mear); if(ctlr->eepromsz == 0){ ctlr->eepromsz = 8-size; ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort)); goto reread; } return data;}static intdp83820reset(Ctlr* ctlr){ int i, r; unsigned char sum; /* * Soft reset the controller; * read the EEPROM to get the initial settings * of the Cfg and Gpior bits which should be cleared by * the reset. */ csr32w(ctlr, Cr, Rst); delay(1); while(csr32r(ctlr, Cr) & Rst) delay(1); atc93c46r(ctlr, 0); if(ctlr->eeprom == nil) return -1; sum = 0; for(i = 0; i < 0x0E; i++){ r = atc93c46r(ctlr, i); ctlr->eeprom[i] = r; sum += r; sum += r>>8; } if(sum != 0){ print("dp83820reset: bad EEPROM checksum\n"); return -1; }#ifdef notdef csr32w(ctlr, Gpior, ctlr->eeprom[4]); cfg = Extstsen|Exd; r = csr32r(ctlr, Cfg); if(ctlr->eeprom[5] & 0x0001) cfg |= Ext125; if(ctlr->eeprom[5] & 0x0002) cfg |= M64addren; if((ctlr->eeprom[5] & 0x0004) && (r & Pci64det)) cfg |= Data64en; if(ctlr->eeprom[5] & 0x0008) cfg |= T64addren; if(!(pcicfgr16(ctlr->pcidev, PciPCR) & 0x10)) cfg |= Mwidis; if(ctlr->eeprom[5] & 0x0020) cfg |= Mrmdis; if(ctlr->eeprom[5] & 0x0080) cfg |= Mode1000; if(ctlr->eeprom[5] & 0x0200) cfg |= Tbien|Mode1000; /* * What about RO bits we might have destroyed with Rst? * What about Exd, Tmrtest, Extstsen, Pintctl? * Why does it think it has detected a 64-bit bus when * it hasn't? */#else //r = csr32r(ctlr, Cfg); //r &= ~(Mode1000|T64addren|Data64en|M64addren); //csr32w(ctlr, Cfg, r); //csr32w(ctlr, Cfg, 0x2000);#endif /* notdef */ ctlr->cfg = csr32r(ctlr, Cfg);print("cfg %8.8uX pcicfg %8.8uX\n", ctlr->cfg, pcicfgr32(ctlr->pcidev, PciPCR)); ctlr->cfg &= ~(T64addren|Data64en|M64addren); csr32w(ctlr, Cfg, ctlr->cfg); csr32w(ctlr, Mibc, Aclr|Frz); return 0;}static voiddp83820pci(void){ void *mem; Pcidev *p; Ctlr *ctlr; p = nil; while(p = pcimatch(p, 0, 0)){ if(p->ccrb != 0x02 || p->ccru != 0) continue; switch((p->did<<16)|p->vid){ default: continue; case (0x0022<<16)|0x100B: /* DP83820 (Gig-NIC) */ break; } mem = vmap(p->mem[1].bar & ~0x0F, p->mem[1].size); if(mem == 0){ print("DP83820: can't map %8.8luX\n", p->mem[1].bar); continue; } ctlr = malloc(sizeof(Ctlr)); ctlr->port = p->mem[1].bar & ~0x0F; ctlr->pcidev = p; ctlr->id = (p->did<<16)|p->vid; ctlr->nic = mem; if(dp83820reset(ctlr)){ free(ctlr); continue; } pcisetbme(p); if(dp83820ctlrhead != nil) dp83820ctlrtail->next = ctlr; else dp83820ctlrhead = ctlr; dp83820ctlrtail = ctlr; }}static intdp83820pnp(Ether* edev){ int i; Ctlr *ctlr; uchar ea[Eaddrlen]; if(dp83820ctlrhead == nil) dp83820pci(); /* * Any adapter matches if no edev->port is supplied, * otherwise the ports must match. */ for(ctlr = dp83820ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; if(edev->port == 0 || edev->port == ctlr->port){ ctlr->active = 1; break; } } if(ctlr == nil) return -1; edev->ctlr = ctlr; edev->port = ctlr->port; edev->irq = ctlr->pcidev->intl; edev->tbdf = ctlr->pcidev->tbdf; edev->mbps = 1000; /* * Check if the adapter's station address is to be overridden. * If not, read it from the EEPROM and set in ether->ea prior to * loading the station address in the hardware. */ memset(ea, 0, Eaddrlen); if(memcmp(ea, edev->ea, Eaddrlen) == 0){ for(i = 0; i < Eaddrlen/2; i++){ edev->ea[2*i] = ctlr->eeprom[0x0C-i]; edev->ea[2*i+1] = ctlr->eeprom[0x0C-i]>>8; } } edev->attach = dp83820attach; edev->transmit = dp83820transmit; edev->interrupt = dp83820interrupt; edev->ifstat = dp83820ifstat; edev->arg = edev; edev->promiscuous = dp83820promiscuous; edev->multicast = dp83820multicast;// edev->shutdown = dp83820shutdown; return 0;}voidetherdp83820link(void){ addethercard("DP83820", dp83820pnp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -