i8254xgbe.cc
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 1,528 行 · 第 1/3 页
CC
1,528 行
igbe->intClock(), true); } if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { DPRINTF(EthernetDesc, "setting tadv\n"); if (!igbe->tadvEvent.scheduled()) { igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() * igbe->intClock()); } } } unusedCache.pop_front(); usedCache.push_back(desc); pktDone = true; pktWaiting = false; pktPtr = NULL; DPRINTF(EthernetDesc, "Descriptor Done\n"); if (igbe->regs.txdctl.wthresh() == 0) { DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n"); writeback(0); } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) { DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); writeback((igbe->cacheBlockSize()-1)>>4); } enableSm(); igbe->checkDrain();}voidIGbE::TxDescCache::serialize(std::ostream &os){ DescCache<TxDesc>::serialize(os); SERIALIZE_SCALAR(pktDone); SERIALIZE_SCALAR(isTcp); SERIALIZE_SCALAR(pktWaiting);}voidIGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string §ion){ DescCache<TxDesc>::unserialize(cp, section); UNSERIALIZE_SCALAR(pktDone); UNSERIALIZE_SCALAR(isTcp); UNSERIALIZE_SCALAR(pktWaiting);}boolIGbE::TxDescCache::packetAvailable(){ if (pktDone) { pktDone = false; return true; } return false;}voidIGbE::TxDescCache::enableSm(){ if (!igbe->drainEvent) { igbe->txTick = true; igbe->restartClock(); }}boolIGbE::TxDescCache::hasOutstandingEvents(){ return pktEvent.scheduled() || wbEvent.scheduled() || fetchEvent.scheduled();}///////////////////////////////////// IGbE /////////////////////////////////voidIGbE::restartClock(){ if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && getState() == SimObject::Running) tickEvent.schedule((curTick/ticks(1)) * ticks(1) + ticks(1));}unsigned intIGbE::drain(Event *de){ unsigned int count; count = pioPort->drain(de) + dmaPort->drain(de); if (rxDescCache.hasOutstandingEvents() || txDescCache.hasOutstandingEvents()) { count++; drainEvent = de; } txFifoTick = false; txTick = false; rxTick = false; if (tickEvent.scheduled()) tickEvent.deschedule(); if (count) changeState(Draining); else changeState(Drained); return count;}voidIGbE::resume(){ SimObject::resume(); txFifoTick = true; txTick = true; rxTick = true; restartClock();}voidIGbE::checkDrain(){ if (!drainEvent) return; txFifoTick = false; txTick = false; rxTick = false; if (!rxDescCache.hasOutstandingEvents() && !txDescCache.hasOutstandingEvents()) { drainEvent->process(); drainEvent = NULL; }}voidIGbE::txStateMachine(){ if (!regs.tctl.en()) { txTick = false; DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n"); return; } // If we have a packet available and it's length is not 0 (meaning it's not // a multidescriptor packet) put it in the fifo, otherwise an the next // iteration we'll get the rest of the data if (txPacket && txDescCache.packetAvailable() && txPacket->length) { bool success; DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); success = txFifo.push(txPacket); txFifoTick = true && !drainEvent; assert(success); txPacket = NULL; txDescCache.writeback((cacheBlockSize()-1)>>4); return; } // Only support descriptor granularity assert(regs.txdctl.gran()); if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) { DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n"); postInterrupt(IT_TXDLOW); } if (!txPacket) { txPacket = new EthPacketData(16384); } if (!txDescCache.packetWaiting()) { if (txDescCache.descLeft() == 0) { postInterrupt(IT_TXQE); txDescCache.writeback(0); txDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing " "writeback stopping ticking and posting TXQE\n"); txTick = false; return; } if (!(txDescCache.descUnused())) { txDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n"); txTick = false; return; } int size; size = txDescCache.getPacketSize(); if (size > 0 && txFifo.avail() > size) { DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining " "DMA of next packet\n", size); txFifo.reserve(size); txDescCache.getPacketData(txPacket); } else if (size <= 0) { DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size); DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n"); txDescCache.writeback(0); } else { DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space " "available in FIFO\n"); txTick = false; } return; } DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n"); txTick = false;}boolIGbE::ethRxPkt(EthPacketPtr pkt){ DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n"); if (!regs.rctl.en()) { DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n"); return true; } // restart the state machines if they are stopped rxTick = true && !drainEvent; if ((rxTick || txTick) && !tickEvent.scheduled()) { DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n"); restartClock(); } if (!rxFifo.push(pkt)) { DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n"); postInterrupt(IT_RXO, true); return false; } return true;}voidIGbE::rxStateMachine(){ if (!regs.rctl.en()) { rxTick = false; DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n"); return; } // If the packet is done check for interrupts/descriptors/etc if (rxDescCache.packetDone()) { rxDmaPacket = false; DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n"); int descLeft = rxDescCache.descLeft(); switch (regs.rctl.rdmts()) { case 2: if (descLeft > .125 * regs.rdlen()) break; case 1: if (descLeft > .250 * regs.rdlen()) break; case 0: if (descLeft > .500 * regs.rdlen()) break; DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n"); postInterrupt(IT_RXDMT); break; } if (descLeft == 0) { rxDescCache.writeback(0); DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing" " writeback and stopping ticking\n"); rxTick = false; } // only support descriptor granulaties assert(regs.rxdctl.gran()); if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) { DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n"); if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4)) rxDescCache.writeback(regs.rxdctl.wthresh()-1); else rxDescCache.writeback((cacheBlockSize()-1)>>4); } if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) && ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) { DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n"); rxDescCache.fetchDescriptors(); } if (rxDescCache.descUnused() == 0) { rxDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " "fetching descriptors and stopping ticking\n"); rxTick = false; } return; } if (rxDmaPacket) { DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); rxTick = false; return; } if (!rxDescCache.descUnused()) { rxDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); rxTick = false; DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n"); return; } if (rxFifo.empty()) { DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n"); rxTick = false; return; } EthPacketPtr pkt; pkt = rxFifo.front(); rxDescCache.writePacket(pkt); DPRINTF(EthernetSM, "RXS: Writing packet into memory\n"); DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n"); rxFifo.pop(); DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); rxTick = false; rxDmaPacket = true;}voidIGbE::txWire(){ if (txFifo.empty()) { txFifoTick = false; return; } if (etherInt->sendPacket(txFifo.front())) { if (DTRACE(EthernetSM)) { IpPtr ip(txFifo.front()); if (ip) DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n", ip->id()); else DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n"); } DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n", txFifo.avail()); txFifo.pop(); } else { // We'll get woken up when the packet ethTxDone() gets called txFifoTick = false; }}voidIGbE::tick(){ DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n"); if (rxTick) rxStateMachine(); if (txTick) txStateMachine(); if (txFifoTick) txWire(); if (rxTick || txTick || txFifoTick) tickEvent.schedule(curTick + ticks(1));}voidIGbE::ethTxDone(){ // restart the tx state machines if they are stopped // fifo to send another packet // tx sm to put more data into the fifo txFifoTick = true && !drainEvent; if (txDescCache.descLeft() != 0 && !drainEvent) txTick = true; restartClock(); DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");}voidIGbE::serialize(std::ostream &os){ PciDev::serialize(os); regs.serialize(os); SERIALIZE_SCALAR(eeOpBits); SERIALIZE_SCALAR(eeAddrBits); SERIALIZE_SCALAR(eeDataBits); SERIALIZE_SCALAR(eeOpcode); SERIALIZE_SCALAR(eeAddr); SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); rxFifo.serialize("rxfifo", os); txFifo.serialize("txfifo", os); bool txPktExists = txPacket; SERIALIZE_SCALAR(txPktExists); if (txPktExists) txPacket->serialize("txpacket", os); Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0, inter_time = 0; if (rdtrEvent.scheduled()) rdtr_time = rdtrEvent.when(); SERIALIZE_SCALAR(rdtr_time); if (radvEvent.scheduled()) radv_time = radvEvent.when(); SERIALIZE_SCALAR(radv_time); if (tidvEvent.scheduled()) tidv_time = tidvEvent.when(); SERIALIZE_SCALAR(tidv_time); if (tadvEvent.scheduled()) tadv_time = tadvEvent.when(); SERIALIZE_SCALAR(tadv_time); if (interEvent.scheduled()) inter_time = interEvent.when(); SERIALIZE_SCALAR(inter_time); nameOut(os, csprintf("%s.TxDescCache", name())); txDescCache.serialize(os); nameOut(os, csprintf("%s.RxDescCache", name())); rxDescCache.serialize(os);}voidIGbE::unserialize(Checkpoint *cp, const std::string §ion){ PciDev::unserialize(cp, section); regs.unserialize(cp, section); UNSERIALIZE_SCALAR(eeOpBits); UNSERIALIZE_SCALAR(eeAddrBits); UNSERIALIZE_SCALAR(eeDataBits); UNSERIALIZE_SCALAR(eeOpcode); UNSERIALIZE_SCALAR(eeAddr); UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); rxFifo.unserialize("rxfifo", cp, section); txFifo.unserialize("txfifo", cp, section); bool txPktExists; UNSERIALIZE_SCALAR(txPktExists); if (txPktExists) { txPacket = new EthPacketData(16384); txPacket->unserialize("txpacket", cp, section); } rxTick = true; txTick = true; txFifoTick = true; Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time; UNSERIALIZE_SCALAR(rdtr_time); UNSERIALIZE_SCALAR(radv_time); UNSERIALIZE_SCALAR(tidv_time); UNSERIALIZE_SCALAR(tadv_time); UNSERIALIZE_SCALAR(inter_time); if (rdtr_time) rdtrEvent.schedule(rdtr_time); if (radv_time) radvEvent.schedule(radv_time); if (tidv_time) tidvEvent.schedule(tidv_time); if (tadv_time) tadvEvent.schedule(tadv_time); if (inter_time) interEvent.schedule(inter_time); txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section)); rxDescCache.unserialize(cp, csprintf("%s.RxDescCache", section));}IGbE *IGbEParams::create(){ return new IGbE(this);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?