diff --git a/src/arch/sparc/miscregfile.cc b/src/arch/sparc/miscregfile.cc index 5bd572d38..f511ef454 100644 --- a/src/arch/sparc/miscregfile.cc +++ b/src/arch/sparc/miscregfile.cc @@ -647,11 +647,9 @@ void MiscRegFile::setReg(int miscReg, return; case MISCREG_CWP: new_val = val >= NWindows ? NWindows - 1 : val; - if (val >= NWindows) { + if (val >= NWindows) new_val = NWindows - 1; - warn("Attempted to set the CWP to %d with NWindows = %d\n", - val, NWindows); - } + tc->changeRegFileContext(CONTEXT_CWP, new_val); break; case MISCREG_GL: diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index c38a9e873..3d08bca1e 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -55,10 +55,10 @@ using namespace iGbReg; using namespace Net; IGbE::IGbE(Params *p) - : PciDev(p), etherInt(NULL), useFlowControl(p->use_flow_control), + : PciDev(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control), rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), - txTick(false), rdtrEvent(this), radvEvent(this), tadvEvent(this), - tidvEvent(this), tickEvent(this), interEvent(this), + txTick(false), txFifoTick(false), rdtrEvent(this), radvEvent(this), + tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this), rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size), txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), clock(p->clock) { @@ -223,6 +223,7 @@ IGbE::read(PacketPtr pkt) pkt->set(regs.rdtr()); if (regs.rdtr.fpd()) { rxDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting interrupt because of RDTR.FPD write\n"); postInterrupt(IT_RXT); regs.rdtr.fpd(0); } @@ -411,6 +412,7 @@ IGbE::write(PacketPtr pkt) regs.itr = val; break; case REG_ICS: + DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n"); postInterrupt((IntTypes)val); break; case REG_IMS: @@ -429,6 +431,7 @@ IGbE::write(PacketPtr pkt) regs.rctl = val; if (regs.rctl.rst()) { rxDescCache.reset(); + DPRINTF(EthernetSM, "RXS: Got RESET!\n"); rxFifo.clear(); regs.rctl.rst(0); } @@ -568,8 +571,8 @@ IGbE::postInterrupt(IntTypes t, bool now) } else { DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n", Clock::Int::ns * 256 * regs.itr.interval()); - assert(!interEvent.scheduled()); - interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); + if (!interEvent.scheduled()) + interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); } } } @@ -676,39 +679,39 @@ IGbE::RxDescCache::pktComplete() // no support for anything but starting at 0 assert(igbe->regs.rxcsum.pcss() == 0); - DPRINTF(EthernetDesc, "RxDesc: Packet written to memory updating Descriptor\n"); + DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n"); uint8_t status = RXDS_DD | RXDS_EOP; uint8_t err = 0; IpPtr ip(pktPtr); if (ip) { if (igbe->regs.rxcsum.ipofld()) { - DPRINTF(EthernetDesc, "RxDesc: Checking IP checksum\n"); + DPRINTF(EthernetDesc, "Checking IP checksum\n"); status |= RXDS_IPCS; desc->csum = htole(cksum(ip)); if (cksum(ip) != 0) { err |= RXDE_IPE; - DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + DPRINTF(EthernetDesc, "Checksum is bad!!\n"); } } TcpPtr tcp(ip); if (tcp && igbe->regs.rxcsum.tuofld()) { - DPRINTF(EthernetDesc, "RxDesc: Checking TCP checksum\n"); + DPRINTF(EthernetDesc, "Checking TCP checksum\n"); status |= RXDS_TCPCS; desc->csum = htole(cksum(tcp)); if (cksum(tcp) != 0) { - DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; } } UdpPtr udp(ip); if (udp && igbe->regs.rxcsum.tuofld()) { - DPRINTF(EthernetDesc, "RxDesc: Checking UDP checksum\n"); + DPRINTF(EthernetDesc, "Checking UDP checksum\n"); status |= RXDS_UDPCS; desc->csum = htole(cksum(udp)); if (cksum(tcp) != 0) { - DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; } } @@ -748,15 +751,18 @@ IGbE::RxDescCache::pktComplete() // If the packet is small enough, interrupt appropriately // I wonder if this is delayed or not?! - if (pktPtr->length <= igbe->regs.rsrpd.idv()) + if (pktPtr->length <= igbe->regs.rsrpd.idv()) { + DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n"); igbe->postInterrupt(IT_SRPD); + } - DPRINTF(EthernetDesc, "RxDesc: Processing of this descriptor complete\n"); + DPRINTF(EthernetDesc, "Processing of this descriptor complete\n"); unusedCache.pop_front(); usedCache.push_back(desc); pktPtr = NULL; enableSm(); pktDone = true; + igbe->checkDrain(); } void @@ -776,11 +782,33 @@ IGbE::RxDescCache::packetDone() return false; } +bool +IGbE::RxDescCache::hasOutstandingEvents() +{ + return pktEvent.scheduled() || wbEvent.scheduled() || + fetchEvent.scheduled(); +} + +void +IGbE::RxDescCache::serialize(std::ostream &os) +{ + DescCache::serialize(os); + SERIALIZE_SCALAR(pktDone); +} + +void +IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string §ion) +{ + DescCache::unserialize(cp, section); + UNSERIALIZE_SCALAR(pktDone); +} + + ///////////////////////////////////// IGbE::TxDesc ///////////////////////////////// IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s) : DescCache(i,n, s), pktDone(false), isTcp(false), pktWaiting(false), - hLen(0), pktEvent(this) + pktEvent(this) { } @@ -792,10 +820,10 @@ IGbE::TxDescCache::getPacketSize() TxDesc *desc; - DPRINTF(EthernetDesc, "TxDesc: Starting processing of descriptor\n"); + DPRINTF(EthernetDesc, "Starting processing of descriptor\n"); while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) { - DPRINTF(EthernetDesc, "TxDesc: Got context descriptor type... skipping\n"); + DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n"); // I think we can just ignore these for now? desc = unusedCache.front(); @@ -813,7 +841,7 @@ IGbE::TxDescCache::getPacketSize() if (!unusedCache.size()) return -1; - DPRINTF(EthernetDesc, "TxDesc: Next TX packet is %d bytes\n", + DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n", TxdOp::getLen(unusedCache.front())); return TxdOp::getLen(unusedCache.front()); @@ -833,9 +861,9 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p) pktWaiting = true; - DPRINTF(EthernetDesc, "TxDesc: Starting DMA of packet\n"); + DPRINTF(EthernetDesc, "Starting DMA of packet\n"); igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), - TxdOp::getLen(desc), &pktEvent, p->data + hLen); + TxdOp::getLen(desc), &pktEvent, p->data + p->length); } @@ -848,7 +876,7 @@ IGbE::TxDescCache::pktComplete() assert(unusedCache.size()); assert(pktPtr); - DPRINTF(EthernetDesc, "TxDesc: DMA of packet complete\n"); + DPRINTF(EthernetDesc, "DMA of packet complete\n"); desc = unusedCache.front(); @@ -857,20 +885,21 @@ IGbE::TxDescCache::pktComplete() DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); if (!TxdOp::eop(desc)) { - assert(hLen == 0); - hLen = TxdOp::getLen(desc); + // This only supports two descriptors per tx packet + assert(pktPtr->length == 0); + pktPtr->length = TxdOp::getLen(desc); unusedCache.pop_front(); usedCache.push_back(desc); pktDone = true; pktWaiting = false; pktPtr = NULL; - DPRINTF(EthernetDesc, "TxDesc: Partial Packet Descriptor Done\n"); + DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n"); return; } // Set the length of the data in the EtherPacket - pktPtr->length = TxdOp::getLen(desc) + hLen; + pktPtr->length += TxdOp::getLen(desc); // no support for vlans assert(!TxdOp::vle(desc)); @@ -888,33 +917,33 @@ IGbE::TxDescCache::pktComplete() // Checksums are only ofloaded for new descriptor types if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { - DPRINTF(EthernetDesc, "TxDesc: Calculating checksums for packet\n"); + DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); IpPtr ip(pktPtr); if (TxdOp::ixsm(desc)) { ip->sum(0); ip->sum(cksum(ip)); - DPRINTF(EthernetDesc, "TxDesc: Calculated IP checksum\n"); + DPRINTF(EthernetDesc, "Calculated IP checksum\n"); } if (TxdOp::txsm(desc)) { if (isTcp) { TcpPtr tcp(ip); tcp->sum(0); tcp->sum(cksum(tcp)); - DPRINTF(EthernetDesc, "TxDesc: Calculated TCP checksum\n"); + DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); } else { UdpPtr udp(ip); udp->sum(0); udp->sum(cksum(udp)); - DPRINTF(EthernetDesc, "TxDesc: Calculated UDP checksum\n"); + DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); } } } if (TxdOp::ide(desc)) { // Deal with the rx timer interrupts - DPRINTF(EthernetDesc, "TxDesc: Descriptor had IDE set\n"); + DPRINTF(EthernetDesc, "Descriptor had IDE set\n"); if (igbe->regs.tidv.idv()) { - DPRINTF(EthernetDesc, "TxDesc: setting tidv\n"); + DPRINTF(EthernetDesc, "setting tidv\n"); if (igbe->tidvEvent.scheduled()) igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() * igbe->intClock()); @@ -924,7 +953,7 @@ IGbE::TxDescCache::pktComplete() } if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { - DPRINTF(EthernetDesc, "TxDesc: setting tadv\n"); + DPRINTF(EthernetDesc, "setting tadv\n"); if (!igbe->tadvEvent.scheduled()) igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() * igbe->intClock()); @@ -939,17 +968,34 @@ IGbE::TxDescCache::pktComplete() pktWaiting = false; pktPtr = NULL; - hLen = 0; - DPRINTF(EthernetDesc, "TxDesc: Descriptor Done\n"); + DPRINTF(EthernetDesc, "Descriptor Done\n"); if (igbe->regs.txdctl.wthresh() == 0) { - DPRINTF(EthernetDesc, "TxDesc: WTHRESH == 0, writing back descriptor\n"); + DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n"); writeback(0); } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) { - DPRINTF(EthernetDesc, "TxDesc: used > WTHRESH, writing back descriptor\n"); + DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); writeback((igbe->cacheBlockSize()-1)>>4); } + igbe->checkDrain(); +} +void +IGbE::TxDescCache::serialize(std::ostream &os) +{ + DescCache::serialize(os); + SERIALIZE_SCALAR(pktDone); + SERIALIZE_SCALAR(isTcp); + SERIALIZE_SCALAR(pktWaiting); +} + +void +IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string §ion) +{ + DescCache::unserialize(cp, section); + UNSERIALIZE_SCALAR(pktDone); + UNSERIALIZE_SCALAR(isTcp); + UNSERIALIZE_SCALAR(pktWaiting); } bool @@ -969,7 +1015,12 @@ IGbE::TxDescCache::enableSm() igbe->restartClock(); } - +bool +IGbE::TxDescCache::hasOutstandingEvents() +{ + return pktEvent.scheduled() || wbEvent.scheduled() || + fetchEvent.scheduled(); +} ///////////////////////////////////// IGbE ///////////////////////////////// @@ -977,10 +1028,61 @@ IGbE::TxDescCache::enableSm() void IGbE::restartClock() { - if (!tickEvent.scheduled() && (rxTick || txTick)) + if (!tickEvent.scheduled() && (rxTick || txTick) && getState() == + SimObject::Running) tickEvent.schedule((curTick/cycles(1)) * cycles(1) + cycles(1)); } +unsigned int +IGbE::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; +} + +void +IGbE::resume() +{ + SimObject::resume(); + + txFifoTick = true; + txTick = true; + rxTick = true; + + restartClock(); +} + +void +IGbE::checkDrain() +{ + if (!drainEvent) + return; + + if (rxDescCache.hasOutstandingEvents() || + txDescCache.hasOutstandingEvents()) { + drainEvent->process(); + drainEvent = NULL; + } +} void IGbE::txStateMachine() @@ -998,8 +1100,10 @@ IGbE::txStateMachine() bool success; DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); success = txFifo.push(txPacket); + txFifoTick = true; assert(success); txPacket = NULL; + txDescCache.writeback((cacheBlockSize()-1)>>4); return; } @@ -1021,6 +1125,7 @@ IGbE::txStateMachine() txDescCache.writeback(0); txTick = false; postInterrupt(IT_TXQE, true); + return; } @@ -1038,11 +1143,17 @@ IGbE::txStateMachine() "DMA of next packet\n", size); txFifo.reserve(size); txDescCache.getPacketData(txPacket); - } else { + } else if (size <= 0) { 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"); + txDescCache.writeback((cacheBlockSize()-1)>>4); + txTick = false; } + return; } } @@ -1095,9 +1206,9 @@ IGbE::rxStateMachine() } if (descLeft == 0) { - DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing writeback\n"); + DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing" + " writeback and stopping ticking\n"); rxDescCache.writeback(0); - DPRINTF(EthernetSM, "RXS: No descriptors left, stopping ticking\n"); rxTick = false; } @@ -1119,9 +1230,9 @@ IGbE::rxStateMachine() } if (rxDescCache.descUnused() == 0) { - DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); + DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " + "fetching descriptors and stopping ticking\n"); rxTick = false; - DPRINTF(EthernetSM, "RXS: Fetching descriptors because none available\n"); rxDescCache.fetchDescriptors(); } return; @@ -1159,15 +1270,18 @@ void IGbE::txWire() { if (txFifo.empty()) { + txFifoTick = false; return; } - txTick = true; if (etherInt->sendPacket(txFifo.front())) { - DPRINTF(Ethernet, "TxFIFO: Successful transmit, bytes in fifo: %d\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; } } @@ -1180,34 +1294,133 @@ IGbE::tick() if (rxTick) rxStateMachine(); - if (txTick) { + if (txTick) txStateMachine(); - txWire(); - } - if (rxTick || txTick) + if (txFifoTick) + txWire(); + + + if (rxTick || txTick || txFifoTick) tickEvent.schedule(curTick + cycles(1)); } void IGbE::ethTxDone() { - // restart the state machines if they are stopped + // 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; txTick = true; + restartClock(); - DPRINTF(Ethernet, "TxFIFO: Transmission complete\n"); + DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n"); } void IGbE::serialize(std::ostream &os) { - panic("Need to implemenet\n"); + 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()) + rdtr_time = tidvEvent.when(); + SERIALIZE_SCALAR(tidv_time); + + if (tadvEvent.scheduled()) + rdtr_time = tadvEvent.when(); + SERIALIZE_SCALAR(tadv_time); + + if (interEvent.scheduled()) + rdtr_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); } void IGbE::unserialize(Checkpoint *cp, const std::string §ion) { - panic("Need to implemenet\n"); + 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)); } diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index a2b9f38d5..2dec3b08c 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -62,8 +62,10 @@ class IGbE : public PciDev uint8_t eeOpcode, eeAddr; uint16_t flash[iGbReg::EEPROM_SIZE]; + // The drain event if we have one + Event *drainEvent; + // cached parameters from params struct - Tick tickRate; bool useFlowControl; // packet fifos @@ -76,24 +78,44 @@ class IGbE : public PciDev // Should to Rx/Tx State machine tick? bool rxTick; bool txTick; + bool txFifoTick; // Event and function to deal with RDTR timer expiring - void rdtrProcess() { rxDescCache.writeback(0); postInterrupt(iGbReg::IT_RXT, true); } + void rdtrProcess() { + rxDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n"); + postInterrupt(iGbReg::IT_RXT, true); + } + //friend class EventWrapper; EventWrapper rdtrEvent; // Event and function to deal with RADV timer expiring - void radvProcess() { rxDescCache.writeback(0); postInterrupt(iGbReg::IT_RXT, true); } + void radvProcess() { + rxDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n"); + postInterrupt(iGbReg::IT_RXT, true); + } + //friend class EventWrapper; EventWrapper radvEvent; // Event and function to deal with TADV timer expiring - void tadvProcess() { postInterrupt(iGbReg::IT_TXDW, true); } + void tadvProcess() { + txDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n"); + postInterrupt(iGbReg::IT_TXDW, true); + } + //friend class EventWrapper; EventWrapper tadvEvent; // Event and function to deal with TIDV timer expiring - void tidvProcess() { postInterrupt(iGbReg::IT_TXDW, true); }; + void tidvProcess() { + txDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n"); + postInterrupt(iGbReg::IT_TXDW, true); + } //friend class EventWrapper; EventWrapper tidvEvent; @@ -131,8 +153,15 @@ class IGbE : public PciDev Tick intClock() { return Clock::Int::ns * 1024; } + /** This function is used to restart the clock so it can handle things like + * draining and resume in one place. */ void restartClock(); + /** Check if all the draining things that need to occur have occured and + * handle the drain event if so. + */ + void checkDrain(); + template class DescCache { @@ -202,8 +231,10 @@ class IGbE : public PciDev */ void areaChanged() { - if (usedCache.size() > 0 || unusedCache.size() > 0) + if (usedCache.size() > 0 || curFetching || wbOut) panic("Descriptor Address, Length or Head changed. Bad\n"); + reset(); + } void writeback(Addr aMask) @@ -229,7 +260,7 @@ class IGbE : public PciDev moreToWb = false; wbAlignment = aMask; - if (max_to_wb + curHead > descLen()) { + if (max_to_wb + curHead >= descLen()) { max_to_wb = descLen() - curHead; moreToWb = true; // this is by definition aligned correctly @@ -265,10 +296,14 @@ class IGbE : public PciDev */ void fetchDescriptors() { - size_t max_to_fetch = descTail() - cachePnt; - if (max_to_fetch < 0) + size_t max_to_fetch; + + if (descTail() >= cachePnt) + max_to_fetch = descTail() - cachePnt; + else max_to_fetch = descLen() - cachePnt; + max_to_fetch = std::min(max_to_fetch, (size - usedCache.size() - unusedCache.size())); @@ -311,8 +346,9 @@ class IGbE : public PciDev #endif cachePnt += curFetching; - if (cachePnt > descLen()) - cachePnt -= descLen(); + assert(cachePnt <= descLen()); + if (cachePnt == descLen()) + cachePnt = 0; curFetching = 0; @@ -320,7 +356,7 @@ class IGbE : public PciDev oldCp, cachePnt); enableSm(); - + igbe->checkDrain(); } EventWrapper fetchEvent; @@ -337,8 +373,8 @@ class IGbE : public PciDev curHead += wbOut; wbOut = 0; - if (curHead > descLen()) - curHead = 0; + if (curHead >= descLen()) + curHead -= descLen(); // Update the head updateHead(curHead); @@ -352,6 +388,7 @@ class IGbE : public PciDev writeback(wbAlignment); } intAfterWb(); + igbe->checkDrain(); } @@ -390,6 +427,63 @@ class IGbE : public PciDev usedCache.clear(); unusedCache.clear(); + + cachePnt = 0; + + } + + virtual void serialize(std::ostream &os) + { + SERIALIZE_SCALAR(cachePnt); + SERIALIZE_SCALAR(curFetching); + SERIALIZE_SCALAR(wbOut); + SERIALIZE_SCALAR(moreToWb); + SERIALIZE_SCALAR(wbAlignment); + + int usedCacheSize = usedCache.size(); + SERIALIZE_SCALAR(usedCacheSize); + for(int x = 0; x < usedCacheSize; x++) { + arrayParamOut(os, csprintf("usedCache_%d", x), + (uint8_t*)usedCache[x],sizeof(T)); + } + + int unusedCacheSize = unusedCache.size(); + SERIALIZE_SCALAR(unusedCacheSize); + for(int x = 0; x < unusedCacheSize; x++) { + arrayParamOut(os, csprintf("unusedCache_%d", x), + (uint8_t*)unusedCache[x],sizeof(T)); + } + } + + virtual void unserialize(Checkpoint *cp, const std::string §ion) + { + UNSERIALIZE_SCALAR(cachePnt); + UNSERIALIZE_SCALAR(curFetching); + UNSERIALIZE_SCALAR(wbOut); + UNSERIALIZE_SCALAR(moreToWb); + UNSERIALIZE_SCALAR(wbAlignment); + + int usedCacheSize; + UNSERIALIZE_SCALAR(usedCacheSize); + T *temp; + for(int x = 0; x < usedCacheSize; x++) { + temp = new T; + arrayParamIn(cp, section, csprintf("usedCache_%d", x), + (uint8_t*)temp,sizeof(T)); + usedCache.push_back(temp); + } + + int unusedCacheSize; + UNSERIALIZE_SCALAR(unusedCacheSize); + for(int x = 0; x < unusedCacheSize; x++) { + temp = new T; + arrayParamIn(cp, section, csprintf("unusedCache_%d", x), + (uint8_t*)temp,sizeof(T)); + unusedCache.push_back(temp); + } + } + virtual bool hasOutstandingEvents() { + return wbEvent.scheduled() || fetchEvent.scheduled(); } }; @@ -428,6 +522,10 @@ class IGbE : public PciDev EventWrapper pktEvent; + virtual bool hasOutstandingEvents(); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); }; friend class RxDescCache; @@ -447,7 +545,6 @@ class IGbE : public PciDev bool pktDone; bool isTcp; bool pktWaiting; - int hLen; public: TxDescCache(IGbE *i, std::string n, int s); @@ -475,6 +572,11 @@ class IGbE : public PciDev void pktComplete(); EventWrapper pktEvent; + virtual bool hasOutstandingEvents(); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + }; friend class TxDescCache; @@ -513,7 +615,8 @@ class IGbE : public PciDev virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - + virtual unsigned int drain(Event *de); + virtual void resume(); }; diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh index 8538c155b..91b3eacc9 100644 --- a/src/dev/i8254xGBe_defs.hh +++ b/src/dev/i8254xGBe_defs.hh @@ -162,7 +162,7 @@ struct TxDesc { namespace TxdOp { const uint8_t TXD_CNXT = 0x0; -const uint8_t TXD_DATA = 0x0; +const uint8_t TXD_DATA = 0x1; bool isLegacy(TxDesc *d) { return !bits(d->d2,29,29); } uint8_t getType(TxDesc *d) { return bits(d->d2, 23,20); } @@ -220,6 +220,14 @@ struct Regs { bool operator==(T d) { return d == _data; } void operator()(T d) { _data = d; } Reg() { _data = 0; } + void serialize(std::ostream &os) + { + SERIALIZE_SCALAR(_data); + } + void unserialize(Checkpoint *cp, const std::string §ion) + { + UNSERIALIZE_SCALAR(_data); + } }; struct CTRL : public Reg { // 0x0000 CTRL Register @@ -595,6 +603,79 @@ struct Regs { ADD_FIELD32(smbclkout,30,1); // smb clock out }; MANC manc; -}; -}; // iGbReg namespace + void serialize(std::ostream &os) + { + paramOut(os, "ctrl", ctrl._data); + paramOut(os, "sts", sts._data); + paramOut(os, "eecd", eecd._data); + paramOut(os, "eerd", eerd._data); + paramOut(os, "ctrl_ext", ctrl_ext._data); + paramOut(os, "mdic", mdic._data); + paramOut(os, "icr", icr._data); + SERIALIZE_SCALAR(imr); + paramOut(os, "itr", itr._data); + SERIALIZE_SCALAR(iam); + paramOut(os, "rctl", rctl._data); + paramOut(os, "fcttv", fcttv._data); + paramOut(os, "tctl", tctl._data); + paramOut(os, "pba", pba._data); + paramOut(os, "fcrtl", fcrtl._data); + paramOut(os, "fcrth", fcrth._data); + paramOut(os, "rdba", rdba._data); + paramOut(os, "rdlen", rdlen._data); + paramOut(os, "rdh", rdh._data); + paramOut(os, "rdt", rdt._data); + paramOut(os, "rdtr", rdtr._data); + paramOut(os, "rxdctl", rxdctl._data); + paramOut(os, "radv", radv._data); + paramOut(os, "rsrpd", rsrpd._data); + paramOut(os, "tdba", tdba._data); + paramOut(os, "tdlen", tdlen._data); + paramOut(os, "tdh", tdh._data); + paramOut(os, "tdt", tdt._data); + paramOut(os, "tidv", tidv._data); + paramOut(os, "txdctl", txdctl._data); + paramOut(os, "tadv", tadv._data); + paramOut(os, "rxcsum", rxcsum._data); + paramOut(os, "manc", manc._data); + } + + void unserialize(Checkpoint *cp, const std::string §ion) + { + paramIn(cp, section, "ctrl", ctrl._data); + paramIn(cp, section, "sts", sts._data); + paramIn(cp, section, "eecd", eecd._data); + paramIn(cp, section, "eerd", eerd._data); + paramIn(cp, section, "ctrl_ext", ctrl_ext._data); + paramIn(cp, section, "mdic", mdic._data); + paramIn(cp, section, "icr", icr._data); + UNSERIALIZE_SCALAR(imr); + paramIn(cp, section, "itr", itr._data); + UNSERIALIZE_SCALAR(iam); + paramIn(cp, section, "rctl", rctl._data); + paramIn(cp, section, "fcttv", fcttv._data); + paramIn(cp, section, "tctl", tctl._data); + paramIn(cp, section, "pba", pba._data); + paramIn(cp, section, "fcrtl", fcrtl._data); + paramIn(cp, section, "fcrth", fcrth._data); + paramIn(cp, section, "rdba", rdba._data); + paramIn(cp, section, "rdlen", rdlen._data); + paramIn(cp, section, "rdh", rdh._data); + paramIn(cp, section, "rdt", rdt._data); + paramIn(cp, section, "rdtr", rdtr._data); + paramIn(cp, section, "rxdctl", rxdctl._data); + paramIn(cp, section, "radv", radv._data); + paramIn(cp, section, "rsrpd", rsrpd._data); + paramIn(cp, section, "tdba", tdba._data); + paramIn(cp, section, "tdlen", tdlen._data); + paramIn(cp, section, "tdh", tdh._data); + paramIn(cp, section, "tdt", tdt._data); + paramIn(cp, section, "tidv", tidv._data); + paramIn(cp, section, "txdctl", txdctl._data); + paramIn(cp, section, "tadv", tadv._data); + paramIn(cp, section, "rxcsum", rxcsum._data); + paramIn(cp, section, "manc", manc._data); + } +}; +} // iGbReg namespace diff --git a/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/config.ini b/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/config.ini index ccb504cd3..06059c3eb 100644 --- a/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/config.ini +++ b/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/config.ini @@ -1,11 +1,7 @@ [root] type=Root children=system -checkpoint= -clock=1000000000000 -max_tick=0 -output_file=cout -progress_interval=0 +dummy=0 [system] type=System diff --git a/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/config.out b/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/config.out index 392fec336..7f9a83d25 100644 --- a/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/config.out +++ b/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/config.out @@ -1,9 +1,6 @@ [root] type=Root -clock=1000000000000 -max_tick=0 -progress_interval=0 -output_file=cout +dummy=0 [system.physmem] type=PhysicalMemory diff --git a/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/m5stats.txt b/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/m5stats.txt index 4fe3d3732..1ed7d50eb 100644 --- a/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/m5stats.txt +++ b/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/m5stats.txt @@ -1,18 +1,18 @@ ---------- Begin Simulation Statistics ---------- -host_inst_rate 104057 # Simulator instruction rate (inst/s) -host_mem_usage 179368 # Number of bytes of host memory used -host_seconds 0.10 # Real time elapsed on the host -host_tick_rate 103746 # Simulator tick rate (ticks/s) +host_inst_rate 65718 # Simulator instruction rate (inst/s) +host_mem_usage 179556 # Number of bytes of host memory used +host_seconds 0.17 # Real time elapsed on the host +host_tick_rate 65601 # Simulator tick rate (ticks/s) sim_freq 1000000000000 # Frequency of simulated ticks -sim_insts 10367 # Number of instructions simulated +sim_insts 11001 # Number of instructions simulated sim_seconds 0.000000 # Number of seconds simulated -sim_ticks 10366 # Number of ticks simulated +sim_ticks 11000 # Number of ticks simulated system.cpu.idle_fraction 0 # Percentage of idle cycles system.cpu.not_idle_fraction 1 # Percentage of non-idle cycles -system.cpu.numCycles 10367 # number of cpu cycles simulated -system.cpu.num_insts 10367 # Number of instructions executed -system.cpu.num_refs 2607 # Number of memory references +system.cpu.numCycles 11001 # number of cpu cycles simulated +system.cpu.num_insts 11001 # Number of instructions executed +system.cpu.num_refs 2760 # Number of memory references system.cpu.workload.PROG:num_syscalls 8 # Number of system calls ---------- End Simulation Statistics ---------- diff --git a/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/stdout b/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/stdout index 567033922..c89235e64 100644 --- a/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/stdout +++ b/tests/quick/02.insttest/ref/sparc/linux/simple-atomic/stdout @@ -7,6 +7,7 @@ CASX FAIL: Passed CASX WORK: Passed LDTX: Passed LDTW: Passed +STTW: Passed Done M5 Simulator System @@ -15,8 +16,9 @@ The Regents of The University of Michigan All Rights Reserved -M5 compiled Mar 6 2007 15:43:35 -M5 started Tue Mar 6 15:52:39 2007 +M5 compiled Mar 29 2007 15:29:35 +M5 started Thu Mar 29 15:39:35 2007 M5 executing on zeep command line: build/SPARC_SE/m5.debug -d build/SPARC_SE/tests/debug/quick/02.insttest/sparc/linux/simple-atomic tests/run.py quick/02.insttest/sparc/linux/simple-atomic -Exiting @ tick 10366 because target called exit() +Global frequency set at 1000000000000 ticks per second +Exiting @ tick 11000 because target called exit()