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), txFifoTick(false), rdtrEvent(this), radvEvent(this),
tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
pktPtr = NULL;
enableSm();
pktDone = true;
+ igbe->checkDrain();
}
void
return false;
}
+bool
+IGbE::RxDescCache::hasOutstandingEvents()
+{
+ return pktEvent.scheduled() || wbEvent.scheduled() ||
+ fetchEvent.scheduled();
+}
+
+void
+IGbE::RxDescCache::serialize(std::ostream &os)
+{
+ DescCache<RxDesc>::serialize(os);
+ SERIALIZE_SCALAR(pktDone);
+}
+
+void
+IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string §ion)
+{
+ DescCache<RxDesc>::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(pktDone);
+}
+
+
///////////////////////////////////// IGbE::TxDesc /////////////////////////////////
IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
: DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
- hLen(0), pktEvent(this)
+ pktEvent(this)
{
}
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);
}
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;
}
// 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));
pktWaiting = false;
pktPtr = NULL;
- hLen = 0;
DPRINTF(EthernetDesc, "Descriptor Done\n");
if (igbe->regs.txdctl.wthresh() == 0) {
DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
writeback((igbe->cacheBlockSize()-1)>>4);
}
+ igbe->checkDrain();
+}
+void
+IGbE::TxDescCache::serialize(std::ostream &os)
+{
+ DescCache<TxDesc>::serialize(os);
+ SERIALIZE_SCALAR(pktDone);
+ SERIALIZE_SCALAR(isTcp);
+ SERIALIZE_SCALAR(pktWaiting);
+}
+
+void
+IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string §ion)
+{
+ DescCache<TxDesc>::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(pktDone);
+ UNSERIALIZE_SCALAR(isTcp);
+ UNSERIALIZE_SCALAR(pktWaiting);
}
bool
igbe->restartClock();
}
-
+bool
+IGbE::TxDescCache::hasOutstandingEvents()
+{
+ return pktEvent.scheduled() || wbEvent.scheduled() ||
+ fetchEvent.scheduled();
+}
///////////////////////////////////// IGbE /////////////////////////////////
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()
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 {
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));
}
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
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 T>
class DescCache
{
oldCp, cachePnt);
enableSm();
-
+ igbe->checkDrain();
}
EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
writeback(wbAlignment);
}
intAfterWb();
+ igbe->checkDrain();
}
}
+ 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();
+ }
+
};
EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
+ virtual bool hasOutstandingEvents();
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string §ion);
};
friend class RxDescCache;
bool pktDone;
bool isTcp;
bool pktWaiting;
- int hLen;
public:
TxDescCache(IGbE *i, std::string n, int s);
void pktComplete();
EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
+ virtual bool hasOutstandingEvents();
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string §ion);
+
};
friend class TxDescCache;
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string §ion);
-
+ virtual unsigned int drain(Event *de);
+ virtual void resume();
};
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<uint32_t> { // 0x0000 CTRL Register
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