📄 ether2114x.c
字号:
Ctlr *ctlr; Des *des; Msgbuf *mb; int i; uchar bi[Easize*2]; ctlr = ether->ctlr; /* * Allocate and initialise the receive ring; * allocate and initialise the transmit ring; * unmask interrupts and start the transmit side; * create and post a setup packet to initialise * the physical ethernet address. */ ctlr->rdr = ialloc(ctlr->nrdr*sizeof(Des), 8*sizeof(ulong)); for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){ des->mb = mballoc(Rbsz, 0, Mbeth2); des->status = Own; des->control = Rbsz; des->addr = PADDR(des->mb->data); } ctlr->rdr[ctlr->nrdr-1].control |= Er; ctlr->rdrx = 0; csr32w(ctlr, 3, PADDR(ctlr->rdr)); ctlr->tdr = ialloc(ctlr->ntdr*sizeof(Des), 8*sizeof(ulong)); ctlr->tdr[ctlr->ntdr-1].control |= Er; ctlr->tdrh = 0; ctlr->tdri = 0; csr32w(ctlr, 4, PADDR(ctlr->tdr)); /* * Clear any bits in the Status Register (CSR5) as * the PNIC has a different reset value from a true 2114x. */ ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti; csr32w(ctlr, 5, ctlr->mask); csr32w(ctlr, 7, ctlr->mask); ctlr->csr6 |= St; csr32w(ctlr, 6, ctlr->csr6); for(i = 0; i < Easize/2; i++){ bi[i*4] = ether->ea[i*2]; bi[i*4+1] = ether->ea[i*2+1]; bi[i*4+2] = ether->ea[i*2+1]; bi[i*4+3] = ether->ea[i*2]; } mb = mballoc(Easize*2*16, 0, Mbeth3); memset(mb->data, 0xFF, sizeof(bi)); for(i = sizeof(bi); i < sizeof(bi)*16; i += sizeof(bi)) memmove(mb->data+i, bi, sizeof(bi)); mb->count = sizeof(bi)*16; ctlr->setupmb = mb; transmit(ether);}static voidcsr9w(Ctlr* ctlr, int data){ csr32w(ctlr, 9, data); microdelay(1);}static intmiimdi(Ctlr* ctlr, int n){ int data, i; /* * Read n bits from the MII Management Register. */ data = 0; for(i = n-1; i >= 0; i--){ if(csr32r(ctlr, 9) & Mdi) data |= (1<<i); csr9w(ctlr, Mii|Mdc); csr9w(ctlr, Mii); } csr9w(ctlr, 0); return data;}static voidmiimdo(Ctlr* ctlr, int bits, int n){ int i, mdo; /* * Write n bits to the MII Management Register. */ for(i = n-1; i >= 0; i--){ if(bits & (1<<i)) mdo = Mdo; else mdo = 0; csr9w(ctlr, mdo); csr9w(ctlr, mdo|Mdc); csr9w(ctlr, mdo); }}static intmiir(Ctlr* ctlr, int phyad, int regad){ int data, i; if(ctlr->id == Pnic){ i = 1000; csr32w(ctlr, 20, 0x60020000|(phyad<<23)|(regad<<18)); do{ microdelay(1); data = csr32r(ctlr, 20); }while((data & 0x80000000) && --i); if(i == 0) return -1; return data & 0xFFFF; } /* * Preamble; * ST+OP+PHYAD+REGAD; * TA + 16 data bits. */ miimdo(ctlr, 0xFFFFFFFF, 32); miimdo(ctlr, 0x1800|(phyad<<5)|regad, 14); data = miimdi(ctlr, 18); if(data & 0x10000) return -1; return data & 0xFFFF;}static voidmiiw(Ctlr* ctlr, int phyad, int regad, int data){ /* * Preamble; * ST+OP+PHYAD+REGAD+TA + 16 data bits; * Z. */ miimdo(ctlr, 0xFFFFFFFF, 32); data &= 0xFFFF; data |= (0x05<<(5+5+2+16))|(phyad<<(5+2+16))|(regad<<(2+16))|(0x02<<16); miimdo(ctlr, data, 32); csr9w(ctlr, Mdc); csr9w(ctlr, 0);}static intsromr(Ctlr* ctlr, int r){ int i, op, data; if(ctlr->id == Pnic){ i = 1000; csr32w(ctlr, 19, 0x600|r); do{ microdelay(1); data = csr32r(ctlr, 19); }while((data & 0x80000000) && --i); return csr32r(ctlr, 9) & 0xFFFF; } /* * This sequence for reading a 16-bit register 'r' * in the EEPROM is taken straight from Section * 7.4 of the 21140 Hardware Reference Manual. */ csr9w(ctlr, Rd|Ss); csr9w(ctlr, Rd|Ss|Scs); csr9w(ctlr, Rd|Ss|Sclk|Scs); csr9w(ctlr, Rd|Ss); op = 0x06; for(i = 3-1; i >= 0; i--){ data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs; csr9w(ctlr, data); csr9w(ctlr, data|Sclk); csr9w(ctlr, data); } for(i = 6-1; i >= 0; i--){ data = Rd|Ss|(((r>>i) & 0x01)<<2)|Scs; csr9w(ctlr, data); csr9w(ctlr, data|Sclk); csr9w(ctlr, data); } data = 0; for(i = 16-1; i >= 0; i--){ csr9w(ctlr, Rd|Ss|Sclk|Scs); if(csr32r(ctlr, 9) & Sdo) data |= (1<<i); csr9w(ctlr, Rd|Ss|Scs); } csr9w(ctlr, 0); return data & 0xFFFF;}static voidsoftreset(Ctlr* ctlr){ /* * Soft-reset the controller and initialise bus mode. * Delay should be >= 50 PCI cycles (2×S @ 25MHz). */ csr32w(ctlr, 0, Swr); microdelay(10); csr32w(ctlr, 0, Rml|Cal16); delay(1);}static inttype5block(Ctlr* ctlr, uchar* block){ int csr15, i, len; /* * Reset or GPR sequence. Reset should be once only, * before the GPR sequence. * Note 'block' is not a pointer to the block head but * a pointer to the data in the block starting at the * reset length value so type5block can be used for the * sequences contained in type 1 and type 3 blocks. * The SROM docs state the 21140 type 5 block is the * same as that for the 21143, but the two controllers * use different registers and sequence-element lengths * so the 21140 code here is a guess for a real type 5 * sequence. */ len = *block++; if(ctlr->id != Tulip3){ for(i = 0; i < len; i++){ csr32w(ctlr, 12, *block); block++; } return len; } for(i = 0; i < len; i++){ csr15 = *block++<<16; csr15 |= *block++<<24; csr32w(ctlr, 15, csr15); debug("%8.8uX ", csr15); } return 2*len;}static inttypephylink(Ctlr* ctlr, uchar*){ int an, bmcr, bmsr, csr6, x; /* * Fail if * auto-negotiataion enabled but not complete; * no valid link established. */ bmcr = miir(ctlr, ctlr->curphyad, Bmcr); miir(ctlr, ctlr->curphyad, Bmsr); bmsr = miir(ctlr, ctlr->curphyad, Bmsr); debug("bmcr 0x%2.2uX bmsr 0x%2.2uX\n", bmcr, bmsr); if(((bmcr & 0x1000) && !(bmsr & 0x0020)) || !(bmsr & 0x0004)) return 0; if(bmcr & 0x1000){ an = miir(ctlr, ctlr->curphyad, Anar); an &= miir(ctlr, ctlr->curphyad, Anlpar) & 0x3E0; debug("an 0x%2.uX 0x%2.2uX 0x%2.2uX\n", miir(ctlr, ctlr->curphyad, Anar), miir(ctlr, ctlr->curphyad, Anlpar), an); if(an & 0x0100) x = 0x4000; else if(an & 0x0080) x = 0x2000; else if(an & 0x0040) x = 0x1000; else if(an & 0x0020) x = 0x0800; else x = 0; } else if((bmcr & 0x2100) == 0x2100) x = 0x4000; else if(bmcr & 0x2000){ /* * If FD capable, force it if necessary. */ if((bmsr & 0x4000) && ctlr->fd){ miiw(ctlr, ctlr->curphyad, Bmcr, 0x2100); x = 0x4000; } else x = 0x2000; } else if(bmcr & 0x0100) x = 0x1000; else x = 0x0800; csr6 = Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; if(ctlr->fdx & x) csr6 |= Fd; if(ctlr->ttm & x) csr6 |= Ttm; debug("csr6 0x%8.8uX 0x%8.8uX 0x%8.8luX\n", csr6, ctlr->csr6, csr32r(ctlr, 6)); if(csr6 != ctlr->csr6){ ctlr->csr6 = csr6; csr32w(ctlr, 6, csr6); } return 1;}static inttypephymode(Ctlr* ctlr, uchar* block, int wait){ uchar *p; int len, mc, nway, phyx, timeo; if(DEBUG){ int i; len = (block[0] & ~0x80)+1; for(i = 0; i < len; i++) debug("%2.2uX ", block[i]); debug("\n"); } if(block[1] == 1) len = 1; else if(block[1] == 3) len = 2; else return -1; /* * Snarf the media capabilities, nway advertisment, * FDX and TTM bitmaps. */ p = &block[5+len*block[3]+len*block[4+len*block[3]]]; mc = *p++; mc |= *p++<<8; nway = *p++; nway |= *p++<<8; ctlr->fdx = *p++; ctlr->fdx |= *p++<<8; ctlr->ttm = *p++; ctlr->ttm |= *p<<8; debug("mc %4.4uX nway %4.4uX fdx %4.4uX ttm %4.4uX\n", mc, nway, ctlr->fdx, ctlr->ttm); USED(mc); phyx = block[2]; ctlr->curphyad = ctlr->phy[phyx]; ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; //csr32w(ctlr, 6, ctlr->csr6); if(typephylink(ctlr, block)) return 0; if(!(ctlr->phyreset & (1<<phyx))){ debug("reset seq: len %d: ", block[3]); if(ctlr->type5block) type5block(ctlr, &ctlr->type5block[2]); else type5block(ctlr, &block[4+len*block[3]]); debug("\n"); ctlr->phyreset |= (1<<phyx); } /* * GPR sequence. */ debug("gpr seq: len %d: ", block[3]); type5block(ctlr, &block[3]); debug("\n"); ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; //csr32w(ctlr, 6, ctlr->csr6); if(typephylink(ctlr, block)) return 0; /* * Turn off auto-negotiation, set the auto-negotiation * advertisment register then start the auto-negotiation * process again. */ miiw(ctlr, ctlr->curphyad, Bmcr, 0); miiw(ctlr, ctlr->curphyad, Anar, nway|1); miiw(ctlr, ctlr->curphyad, Bmcr, 0x1000); if(!wait) return 0; for(timeo = 0; timeo < 30; timeo++){ if(typephylink(ctlr, block)) return 0; delay(100); } return -1;}static inttype0link(Ctlr* ctlr, uchar* block){ int m, polarity, sense; m = (block[3]<<8)|block[2]; sense = 1<<((m & 0x000E)>>1); if(m & 0x0080) polarity = sense; else polarity = 0; return (csr32r(ctlr, 12) & sense)^polarity;}static inttype0mode(Ctlr* ctlr, uchar* block, int wait){ int csr6, m, timeo; csr6 = Sc|Mbo|Hbd|Ca|Sb|TrMODE;debug("type0: medium 0x%uX, fd %d: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n", ctlr->medium, ctlr->fd, block[0], block[1], block[2], block[3]); switch(block[0]){ default: break; case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ /* * Don't attempt full-duplex * unless explicitly requested. */ if(!ctlr->fd) return -1; csr6 |= Fd; break; } m = (block[3]<<8)|block[2]; if(m & 0x0001) csr6 |= Ps; if(m & 0x0010) csr6 |= Ttm; if(m & 0x0020) csr6 |= Pcs; if(m & 0x0040) csr6 |= Scr; csr32w(ctlr, 12, block[1]); microdelay(10); csr32w(ctlr, 6, csr6); ctlr->csr6 = csr6; if(!wait) return 0; for(timeo = 0; timeo < 30; timeo++){ if(type0link(ctlr, block)) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -