📄 etherigbe.c
字号:
len = BLEN(bp); print("txstart: extended short pkt %d -> %d bytes\n", olen, len); } /* set up a descriptor for it */ tdesc = &ctlr->tdba[tdt]; tdesc->addr[0] = PCIWADDR(bp->rp); tdesc->addr[1] = 0; tdesc->control = /* Ide| */ Rs|Dext|Ifcs|Teop|DtypeDD|len; tdesc->status = 0; ctlr->tb[tdt] = bp; } ctlr->tdt = tdt; csr32w(ctlr, Tdt, tdt); igbeim(ctlr, Txdw);}static Block *fromringbuf(Ether *ether){ RingBuf *tb = ðer->tb[ether->ti]; Block *bp = allocb(tb->len); memmove(bp->wp, tb->pkt, tb->len); memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); bp->wp += tb->len; return bp;}static voidigbetransmit(Ether* edev){ Block *bp; Ctlr *ctlr; Tdesc *tdesc; RingBuf *tb; int tdh; /* * For now there are no smarts here. Tuning comes later. */ ctlr = edev->ctlr; ilock(&ctlr->tdlock); /* * Free any completed packets * - try to get the soft tdh to catch the tdt; * - if the packet had an underrun bump the threshold * - the Tu bit doesn't seem to ever be set, perhaps * because Rs mode is used? */ tdh = ctlr->tdh; for(;;){ tdesc = &ctlr->tdba[tdh]; if(!(tdesc->status & Tdd)) break; if(tdesc->status & Tu){ ctlr->ett++; csr32w(ctlr, Ett, ctlr->ett); } tdesc->status = 0; if(ctlr->tb[tdh] != nil){ freeb(ctlr->tb[tdh]); ctlr->tb[tdh] = nil; } tdh = NEXT(tdh, Ntdesc); } ctlr->tdh = tdh; /* copy packets from the software RingBuf to the transmission q */ /* from boot ether83815.c */ while((tb = &edev->tb[edev->ti])->owner == Interface){ bp = fromringbuf(edev); /* put the buffer on the transmit queue */ if(ctlr->bqhead) ctlr->bqtail->next = bp; else ctlr->bqhead = bp; ctlr->bqtail = bp; txstart(edev); /* kick transmitter */ tb->owner = Host; /* give descriptor back */ edev->ti = NEXT(edev->ti, edev->ntb); } iunlock(&ctlr->tdlock);}static voidigbereplenish(Ctlr* ctlr){ int rdt; Block *bp; Rdesc *rdesc; rdt = ctlr->rdt; while(NEXT(rdt, Nrdesc) != ctlr->rdh){ rdesc = &ctlr->rdba[rdt]; if(ctlr->rb[rdt] != nil){ /* nothing to do */ } else if((bp = iallocb(2048)) != nil){ ctlr->rb[rdt] = bp; rdesc->addr[0] = PCIWADDR(bp->rp); rdesc->addr[1] = 0; } else break; rdesc->status = 0; rdt = NEXT(rdt, Nrdesc); } ctlr->rdt = rdt; csr32w(ctlr, Rdt, rdt);}static voidtoringbuf(Ether *ether, Block *bp){ RingBuf *rb = ðer->rb[ether->ri]; if (rb->owner == Interface) { rb->len = BLEN(bp); memmove(rb->pkt, bp->rp, rb->len); rb->owner = Host; ether->ri = NEXT(ether->ri, ether->nrb); } /* else no one is expecting packets from the network */}static voidigbeinterrupt(Ureg*, void* arg){ Block *bp; Ctlr *ctlr; Ether *edev; Rdesc *rdesc; int icr, im, rdh, txdw = 0; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->imlock); csr32w(ctlr, Imc, ~0); im = ctlr->im; for(icr = csr32r(ctlr, Icr); icr & ctlr->im; icr = csr32r(ctlr, Icr)){ /* * Link status changed. */ if(icr & (Rxseq|Lsc)){ /* * More here... */ } /* * Process any received packets. */ rdh = ctlr->rdh; for(;;){ rdesc = &ctlr->rdba[rdh]; if(!(rdesc->status & Rdd)) break; if ((rdesc->status & Reop) && rdesc->errors == 0) { bp = ctlr->rb[rdh]; ctlr->rb[rdh] = nil; /* * it appears that the original 82543 needed * to have the Ethernet CRC excluded, but that * the newer chips do not? */ bp->wp += rdesc->length /* -4 */; toringbuf(edev, bp); freeb(bp); } else if ((rdesc->status & Reop) && rdesc->errors) print("igbe: input packet error 0x%ux\n", rdesc->errors); rdesc->status = 0; rdh = NEXT(rdh, Nrdesc); } ctlr->rdh = rdh; if(icr & Rxdmt0) igbereplenish(ctlr); if(icr & Txdw){ im &= ~Txdw; txdw++; } } ctlr->im = im; csr32w(ctlr, Ims, im); iunlock(&ctlr->imlock); if(txdw) igbetransmit(edev);}static intigbeinit(Ether* edev){ int csr, i, r, ctrl; MiiPhy *phy; Ctlr *ctlr; ctlr = edev->ctlr; /* * Set up the receive addresses. * There are 16 addresses. The first should be the MAC address. * The others are cleared and not marked valid (MS bit of Rah). */ csr = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0]; csr32w(ctlr, Ral, csr); csr = 0x80000000|(edev->ea[5]<<8)|edev->ea[4]; csr32w(ctlr, Rah, csr); for(i = 1; i < 16; i++){ csr32w(ctlr, Ral+i*8, 0); csr32w(ctlr, Rah+i*8, 0); } /* * Clear the Multicast Table Array. * It's a 4096 bit vector accessed as 128 32-bit registers. */ for(i = 0; i < 128; i++) csr32w(ctlr, Mta+i*4, 0); /* * Receive initialisation. * Mostly defaults from the datasheet, will * need some tuning for performance: * Rctl descriptor mimimum threshold size * discard pause frames * strip CRC * Rdtr interrupt delay * Rxdctl all the thresholds */ csr32w(ctlr, Rctl, 0); /* * Allocate the descriptor ring and load its * address and length into the NIC. */ ctlr->rdba = xspanalloc(Nrdesc*sizeof(Rdesc), 128 /* was 16 */, 0); csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba)); csr32w(ctlr, Rdbah, 0); csr32w(ctlr, Rdlen, Nrdesc*sizeof(Rdesc)); /* * Initialise the ring head and tail pointers and * populate the ring with Blocks. * The datasheet says the tail pointer is set to beyond the last * descriptor hardware can process, which implies the initial * condition is Rdh == Rdt. However, experience shows Rdt must * always be 'behind' Rdh; the replenish routine ensures this. */ ctlr->rdh = 0; csr32w(ctlr, Rdh, ctlr->rdh); ctlr->rdt = 0; csr32w(ctlr, Rdt, ctlr->rdt); ctlr->rb = malloc(sizeof(Block*)*Nrdesc); igbereplenish(ctlr); /* * Set up Rctl but don't enable receiver (yet). */ csr32w(ctlr, Rdtr, 0); switch(ctlr->id){ case i82540em: case i82540eplp: case i82541gi: case i82541pi: case i82546gb: case i82546eb: case i82547gi: csr32w(ctlr, Radv, 64); break; } csr32w(ctlr, Rxdctl, (8<<WthreshSHIFT)|(8<<HthreshSHIFT)|4); /* * Enable checksum offload. */ csr32w(ctlr, Rxcsum, Tuofl|Ipofl|(ETHERHDRSIZE<<PcssSHIFT)); csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF); igbeim(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq); /* * Transmit initialisation. * Mostly defaults from the datasheet, will * need some tuning for performance. The normal mode will * be full-duplex and things to tune for half-duplex are * Tctl re-transmit on late collision * Tipg all IPG times * Tbt burst timer * Ait adaptive IFS throttle * and in general * Txdmac packet prefetching * Ett transmit early threshold * Tidv interrupt delay value * Txdctl all the thresholds */ csr32w(ctlr, Tctl, (0x0F<<CtSHIFT)|Psp|(66<<ColdSHIFT)); /* Fd */ switch(ctlr->id){ default: r = 6; break; case i82543gc: case i82544ei: case i82547ei: case i82540em: case i82540eplp: case i82541gi: case i82541pi: case i82546gb: case i82546eb: case i82547gi: r = 8; break; } csr32w(ctlr, Tipg, (6<<20)|(8<<10)|r); csr32w(ctlr, Ait, 0); csr32w(ctlr, Txdmac, 0); csr32w(ctlr, Tidv, 128); /* * Allocate the descriptor ring and load its * address and length into the NIC. */ ctlr->tdba = xspanalloc(Ntdesc*sizeof(Tdesc), 128 /* was 16 */, 0); csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba)); csr32w(ctlr, Tdbah, 0); csr32w(ctlr, Tdlen, Ntdesc*sizeof(Tdesc)); /* * Initialise the ring head and tail pointers. */ ctlr->tdh = 0; csr32w(ctlr, Tdh, ctlr->tdh); ctlr->tdt = 0; csr32w(ctlr, Tdt, ctlr->tdt); ctlr->tb = malloc(sizeof(Block*)*Ntdesc);// ctlr->im |= Txqe|Txdw; r = (4<<WthreshSHIFT)|(4<<HthreshSHIFT)|(8<<PthreshSHIFT); switch(ctlr->id){ default: break; case i82540em: case i82540eplp: case i82547gi: case i82541pi: case i82546gb: case i82546eb: case i82541gi: r = csr32r(ctlr, Txdctl); r &= ~WthreshMASK; r |= Gran|(4<<WthreshSHIFT); csr32w(ctlr, Tadv, 64); break; } csr32w(ctlr, Txdctl, r); r = csr32r(ctlr, Tctl); r |= Ten; csr32w(ctlr, Tctl, r); if(ctlr->mii == nil || ctlr->mii->curphy == nil) { print("igbe: no mii (yet)\n"); return 0; } /* wait for the link to come up */ if (miistatus(ctlr->mii) < 0) return -1; print("igbe: phy: "); phy = ctlr->mii->curphy; if (phy->fd) print("full duplex"); else print("half duplex"); print(", %d Mb/s\n", phy->speed); /* * Flow control. */ ctrl = csr32r(ctlr, Ctrl); if(phy->rfc) ctrl |= Rfce; if(phy->tfc) ctrl |= Tfce; csr32w(ctlr, Ctrl, ctrl); return 0;}static inti82543mdior(Ctlr* ctlr, int n){ int ctrl, data, i, r; /* * Read n bits from the Management Data I/O Interface. */ ctrl = csr32r(ctlr, Ctrl); r = (ctrl & ~Mddo)|Mdco; data = 0; for(i = n-1; i >= 0; i--){ if(csr32r(ctlr, Ctrl) & Mdd) data |= (1<<i); csr32w(ctlr, Ctrl, Mdc|r); csr32w(ctlr, Ctrl, r); } csr32w(ctlr, Ctrl, ctrl); return data;}static inti82543mdiow(Ctlr* ctlr, int bits, int n){ int ctrl, i, r; /* * Write n bits to the Management Data I/O Interface. */ ctrl = csr32r(ctlr, Ctrl); r = Mdco|Mddo|ctrl; for(i = n-1; i >= 0; i--){ if(bits & (1<<i)) r |= Mdd; else r &= ~Mdd; csr32w(ctlr, Ctrl, Mdc|r); csr32w(ctlr, Ctrl, r); } csr32w(ctlr, Ctrl, ctrl); return 0;}static inti82543miimir(Mii* mii, int pa, int ra){ int data; Ctlr *ctlr; ctlr = mii->ctlr; /* * MII Management Interface Read. * * Preamble; * ST+OP+PHYAD+REGAD; * TA + 16 data bits. */ i82543mdiow(ctlr, 0xFFFFFFFF, 32); i82543mdiow(ctlr, 0x1800|(pa<<5)|ra, 14); data = i82543mdior(ctlr, 18); if(data & 0x10000) return -1; return data & 0xFFFF;}static inti82543miimiw(Mii* mii, int pa, int ra, int data){ Ctlr *ctlr; ctlr = mii->ctlr; /* * MII Management Interface Write. * * Preamble; * ST+OP+PHYAD+REGAD+TA + 16 data bits; * Z. */ i82543mdiow(ctlr, 0xFFFFFFFF, 32); data &= 0xFFFF; data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16); i82543mdiow(ctlr, data, 32); return 0;}static intigbemiimir(Mii* mii, int pa, int ra){ Ctlr *ctlr; int mdic, timo; ctlr = mii->ctlr; csr32w(ctlr, Mdic, MDIrop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)); mdic = 0; for(timo = 64; timo; timo--){ mdic = csr32r(ctlr, Mdic); if(mdic & (MDIe|MDIready)) break; microdelay(1); } if((mdic & (MDIe|MDIready)) == MDIready) return mdic & 0xFFFF; return -1;}static intigbemiimiw(Mii* mii, int pa, int ra, int data){ Ctlr *ctlr; int mdic, timo; ctlr = mii->ctlr; data &= MDIdMASK; csr32w(ctlr, Mdic, MDIwop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)|data); mdic = 0; for(timo = 64; timo; timo--){ mdic = csr32r(ctlr, Mdic); if(mdic & (MDIe|MDIready)) break; microdelay(1); } if((mdic & (MDIe|MDIready)) == MDIready) return 0; return -1;}static intigbemii(Ctlr* ctlr){ MiiPhy *phy = (MiiPhy *)1; int ctrl, p, r; USED(phy); r = csr32r(ctlr, Status); if(r & Tbimode) return -1; if((ctlr->mii = malloc(sizeof(Mii))) == nil) return -1; ctlr->mii->ctlr = ctlr; ctrl = csr32r(ctlr, Ctrl); ctrl |= Slu; switch(ctlr->id){ case i82543gc: ctrl |= Frcdplx|Frcspd; csr32w(ctlr, Ctrl, ctrl); /* * The reset pin direction (Mdro) should already * be set from the EEPROM load. * If it's not set this configuration is unexpected * so bail. */ r = csr32r(ctlr, Ctrlext); if(!(r & Mdro)) return -1; csr32w(ctlr, Ctrlext, r); delay(20); r = csr32r(ctlr, Ctrlext);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -