📄 ether83815.c
字号:
if(status & Txurn){ ctlr->txurn++; ilock(&ctlr->lock); /* change threshold */ iunlock(&ctlr->lock); status &= ~(Txurn); } ilock(&ctlr->tlock); while(ctlr->ntq){ des = &ctlr->tdr[ctlr->tdri]; cmdsts = des->cmdsts; if(cmdsts & Own) break; if((cmdsts & Ok) == 0){ if(cmdsts & Txa) ctlr->txa++; if(cmdsts & Tfu) ctlr->tfu++; if(cmdsts & Td) ctlr->td++; if(cmdsts & Ed) ctlr->ed++; if(cmdsts & Owc) ctlr->owc++; if(cmdsts & Ec) ctlr->ec++;#ifndef FS ether->oerrs++;#endif } freeb(des->bp); des->bp = nil; des->cmdsts = 0; ctlr->ntq--; ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr); } txstart(ether); iunlock(&ctlr->tlock); status &= ~(Txurn|Txidle|Txerr|Txdesc|Txok); /* * Anything left not catered for? */ if(status) print("#l%d: status %8.8uX\n", ether->ctlrno, status); }}static voidctlrinit(Ether* ether){ Ctlr *ctlr; Des *des, *last; ctlr = ether->ctlr; /* * Allocate suitable aligned descriptors * for the transmit and receive rings; * initialise the receive ring; * initialise the transmit ring; * unmask interrupts and start the transmit side. */ des = xspanalloc((ctlr->nrdr+ctlr->ntdr)*sizeof(Des), 32, 0); if(des == nil) { print("ns83815: ctlrinit: iallocb of descs. failed\n"); return; } ctlr->tdr = des; ctlr->rdr = des+ctlr->ntdr; last = nil; for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){ des->bp = iallocb(Rbsz); if(des->bp == nil) error(Enomem); des->cmdsts = Rbsz; des->addr = PADDR(des->bp->rp); if(last != nil) last->next = PADDR(des); last = des; } ctlr->rdr[ctlr->nrdr-1].next = PADDR(ctlr->rdr); ctlr->rdrx = 0; csr32w(ctlr, Rrxdp, PADDR(ctlr->rdr)); last = nil; for(des = ctlr->tdr; des < &ctlr->tdr[ctlr->ntdr]; des++){ des->cmdsts = 0; des->bp = nil; des->addr = ~0; if(last != nil) last->next = PADDR(des); last = des; } ctlr->tdr[ctlr->ntdr-1].next = PADDR(ctlr->tdr); ctlr->tdrh = 0; ctlr->tdri = 0; csr32w(ctlr, Rtxdp, PADDR(ctlr->tdr)); txrxcfg(ctlr, Drth512); csr32w(ctlr, Rimr, Dperr|Sserr|Rmabt|Rtabt|Rxsovr|Hiberr|Txurn|Txerr|Txdesc|Txok|Rxorn|Rxerr|Rxdesc|Rxok); /* Phy|Pme|Mib */ csr32r(ctlr, Risr); /* clear status */ csr32w(ctlr, Rier, Ie);err: ;}static voideeclk(Ctlr *ctlr, int clk){ csr32w(ctlr, Rmear, Eesel | clk); microdelay(2);}static voideeidle(Ctlr *ctlr){ int i; eeclk(ctlr, 0); eeclk(ctlr, Eeclk); for(i=0; i<25; i++){ eeclk(ctlr, 0); eeclk(ctlr, Eeclk); } eeclk(ctlr, 0); csr32w(ctlr, Rmear, 0); microdelay(2);}static inteegetw(Ctlr *ctlr, int a){ int d, i, w, v; eeidle(ctlr); eeclk(ctlr, 0); eeclk(ctlr, Eeclk); d = 0x180 | a; for(i=0x400; i; i>>=1){ v = (d & i) ? Eedi : 0; eeclk(ctlr, v); eeclk(ctlr, Eeclk|v); } eeclk(ctlr, 0); w = 0; for(i=0x8000; i; i >>= 1){ eeclk(ctlr, Eeclk); if(csr32r(ctlr, Rmear) & Eedo) w |= i; microdelay(2); eeclk(ctlr, 0); } eeidle(ctlr); return w;}static voidresetctlr(Ctlr *ctlr){ int i; csr32w(ctlr, Rcr, Rst); for(i=0;; i++){ if(i > 100) panic("ns83815: soft reset did not complete"); microdelay(250); if((csr32r(ctlr, Rcr) & Rst) == 0) break; delay(1); }}static voidshutdown(Ether* ether){ Ctlr *ctlr = ether->ctlr;print("ether83815 shutting down\n"); csr32w(ctlr, Rcr, Rxd|Txd); /* disable transceiver */ resetctlr(ctlr);}static voidsoftreset(Ctlr* ctlr, int resetphys){ int i, w; /* * Soft-reset the controller */ resetctlr(ctlr); csr32w(ctlr, Rccsr, Pmests); csr32w(ctlr, Rccsr, 0); csr32w(ctlr, Rcfg, csr32r(ctlr, Rcfg) | Pint_acen); if(resetphys){ /* * Soft-reset the PHY */ csr32w(ctlr, Rbmcr, Reset); for(i=0;; i++){ if(i > 100) panic("ns83815: PHY soft reset time out"); if((csr32r(ctlr, Rbmcr) & Reset) == 0) break; delay(1); } } /* * Initialisation values, in sequence (see 4.4 Recommended Registers Configuration) */ csr16w(ctlr, 0xCC, 0x0001); /* PGSEL */ csr16w(ctlr, 0xE4, 0x189C); /* PMCCSR */ csr16w(ctlr, 0xFC, 0x0000); /* TSTDAT */ csr16w(ctlr, 0xF4, 0x5040); /* DSPCFG */ csr16w(ctlr, 0xF8, 0x008C); /* SDCFG */ /* * Auto negotiate */ w = csr16r(ctlr, Rbmsr); /* clear latched bits */ debug("anar: %4.4ux\n", csr16r(ctlr, Ranar)); csr16w(ctlr, Rbmcr, Anena); if(csr16r(ctlr, Ranar) == 0 || (csr32r(ctlr, Rcfg) & Aneg_dn) == 0){ csr16w(ctlr, Rbmcr, Anena|Anrestart); for(i=0;; i++){ if(i > 6000){ print("ns83815: auto neg timed out\n"); break; } if((w = csr16r(ctlr, Rbmsr)) & Ancomp) break; delay(1); } debug("%d ms\n", i); w &= 0xFFFF; debug("bmsr: %4.4ux\n", w); } USED(w); debug("anar: %4.4ux\n", csr16r(ctlr, Ranar)); debug("anlpar: %4.4ux\n", csr16r(ctlr, Ranlpar)); debug("aner: %4.4ux\n", csr16r(ctlr, Raner)); debug("physts: %4.4ux\n", csr16r(ctlr, Rphysts)); debug("tbscr: %4.4ux\n", csr16r(ctlr, Rtbscr));}static intmedia(Ether* ether){ Ctlr* ctlr; ulong cfg; ctlr = ether->ctlr; cfg = csr32r(ctlr, Rcfg); ctlr->fd = (cfg & Fdup) != 0; if(cfg & Speed100) return 100; if((cfg & Lnksts) == 0) return 100; /* no link: use 100 to ensure larger queues */ return 10;}static char* mediatable[9] = { "10BASE-T", /* TP */ "10BASE-2", /* BNC */ "10BASE-5", /* AUI */ "100BASE-TX", "10BASE-TFD", "100BASE-TXFD", "100BASE-T4", "100BASE-FX", "100BASE-FXFD",};static intis630(ulong id, Pcidev *p){ if(id == SiS900) switch (p->rid) { case SiSrev630s: case SiSrev630e: case SiSrev630ea1: return 1; } return 0;}enum { MagicReg = 0x48, MagicRegSz = 1, Magicrden = 0x40, /* read enable, apparently */ Paddr= 0x70, /* address port */ Pdata= 0x71, /* data port */ Pcinetctlr = 2,};/* rcmos() originally from LANL's SiS 900 driver's rcmos() */static intsisrdcmos(Ctlr *ctlr){ int i; unsigned reg; ulong port; Pcidev *p; debug("ns83815: SiS 630 rev. %ux reading mac address from cmos\n", ctlr->pcidev->rid); p = pcimatch(nil, SiS, SiS630bridge); if(p == nil) { print("ns83815: no SiS 630 rev. %ux bridge for mac addr\n", ctlr->pcidev->rid); return 0; } port = p->mem[0].bar & ~0x01; debug("ns83815: SiS 630 rev. %ux reading mac addr from cmos via bridge at port 0x%lux\n", ctlr->pcidev->rid, port); reg = pcicfgr8(p, MagicReg); pcicfgw8(p, MagicReg, reg|Magicrden); for (i = 0; i < Eaddrlen; i++) { outb(port+Paddr, SiS630eenodeaddr + i); ctlr->sromea[i] = inb(port+Pdata); } pcicfgw8(p, MagicReg, reg & ~Magicrden); return 1;}/* * If this is a SiS 630E chipset with an embedded SiS 900 controller, * we have to read the MAC address from the APC CMOS RAM. - sez freebsd. * However, CMOS *is* NVRAM normally. See devrtc.c:440, memory.c:88. */static voidsissrom(Ctlr *ctlr){ union { uchar eaddr[Eaddrlen]; ushort alignment; } ee; int i, off = SiSeenodeaddr, cnt = sizeof ee.eaddr / sizeof(short); ushort *shp = (ushort *)ee.eaddr; if(!is630(ctlr->id, ctlr->pcidev) || !sisrdcmos(ctlr)) { for (i = 0; i < cnt; i++) *shp++ = eegetw(ctlr, off++); memmove(ctlr->sromea, ee.eaddr, sizeof ctlr->sromea); }}static voidnssrom(Ctlr* ctlr){ int i, j; for(i = 0; i < nelem(ctlr->srom); i++) ctlr->srom[i] = eegetw(ctlr, i); /* * the MAC address is reversed, straddling word boundaries */ j = Nseenodeaddr*16 + 15; for(i=0; i<48; i++){ ctlr->sromea[i>>3] |= ((ctlr->srom[j>>4] >> (15-(j&0xF))) & 1) << (i&7); j++; }}static voidsrom(Ctlr* ctlr){ memset(ctlr->sromea, 0, sizeof(ctlr->sromea)); switch (ctlr->id) { case SiS900: case SiS7016: sissrom(ctlr); break; case Nat83815: nssrom(ctlr); break; default: print("ns83815: srom: unknown id 0x%ux\n", ctlr->id); break; }}static voidscanpci83815(void){ Ctlr *ctlr; Pcidev *p; ulong id; p = nil; while(p = pcimatch(p, 0, 0)){ /* ccru is a short in the FS kernel, thus the cast to uchar */ if (p->ccrb != Pcinetctlr || (uchar)p->ccru != 0) continue; /* not a nic */ id = (p->did<<16)|p->vid; switch(id){ default: continue; case Nat83815: case SiS900: break; } /* * bar[0] is the I/O port register address and * bar[1] is the memory-mapped register address. */ ctlr = mallocz(sizeof(Ctlr), 1); ctlr->port = p->mem[0].bar & ~0x01; ctlr->pcidev = p; ctlr->id = id; if(ioalloc(ctlr->port, p->mem[0].size, 0, "ns83815") < 0){ print("ns83815: port 0x%uX in use\n", ctlr->port); free(ctlr); continue; } softreset(ctlr, 0); srom(ctlr); if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; }}/* multicast already on, don't need to do anything */static voidmulticast(void*, uchar*, int){}intdp83815reset(Ether* ether){ Ctlr *ctlr; int i, x; ulong ctladdr; uchar ea[Eaddrlen]; static int scandone; if(scandone == 0){ scanpci83815(); scandone = 1; } /* * Any adapter matches if no ether->port is supplied, * otherwise the ports must match. */ for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; if(ether->port == 0 || ether->port == ctlr->port){ ctlr->active = 1; break; } } if(ctlr == nil) return -1; ether->ctlr = ctlr; ether->port = ctlr->port; ether->irq = ctlr->pcidev->intl; ether->tbdf = ctlr->pcidev->tbdf; /* * 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, ether->ea, Eaddrlen) == 0) memmove(ether->ea, ctlr->sromea, Eaddrlen); for(i=0; i<Eaddrlen; i+=2){ x = ether->ea[i] | (ether->ea[i+1]<<8); ctladdr = (ctlr->id == Nat83815? i: i<<15); csr32w(ctlr, Rrfcr, ctladdr); csr32w(ctlr, Rrfdr, x); } csr32w(ctlr, Rrfcr, Rfen|Apm|Aab|Aam); ether->mbps = media(ether); /* * Look for a medium override in case there's no autonegotiation * the autonegotiation fails. */ for(i = 0; i < ether->nopt; i++){ if(cistrcmp(ether->opt[i], "FD") == 0){ ctlr->fd = 1; continue; } for(x = 0; x < nelem(mediatable); x++){ debug("compare <%s> <%s>\n", mediatable[x], ether->opt[i]); if(cistrcmp(mediatable[x], ether->opt[i]) == 0){ if(x != 4 && x >= 3) ether->mbps = 100; else ether->mbps = 10; switch(x){ default: ctlr->fd = 0; break; case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ ctlr->fd = 1; break; } break; } } } /* * Initialise descriptor rings, ethernet address. */ ctlr->nrdr = Nrde; ctlr->ntdr = Ntde; pcisetbme(ctlr->pcidev); ctlrinit(ether); /* * Linkage to the generic ethernet driver. */ ether->attach = attach; ether->transmit = transmit; ether->interrupt = interrupt;#ifndef FS ether->ifstat = ifstat; ether->arg = ether; ether->promiscuous = promiscuous; ether->multicast = multicast; ether->shutdown = shutdown;#endif debug("ns83815: dp83815reset: done\n"); return 0;}#ifndef FSvoidether83815link(void){ addethercard("83815", dp83815reset);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -