From 6248e12704275bf4cc88f1743bb3a4bff7adcf9f Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Wed, 13 Aug 2008 17:41:58 -0400 Subject: [PATCH] Add the ability to specify a think time before descriptor fetch/writeback starts/ends as well as after read/write dmas --- src/dev/Ethernet.py | 7 +++++ src/dev/i8254xGBe.cc | 10 ++++-- src/dev/i8254xGBe.hh | 75 +++++++++++++++++++++++++++++++++----------- 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/dev/Ethernet.py b/src/dev/Ethernet.py index 2beb0d537..01384b32b 100644 --- a/src/dev/Ethernet.py +++ b/src/dev/Ethernet.py @@ -98,6 +98,13 @@ class IGbE(EtherDevice): InterruptLine = 0x1e InterruptPin = 0x01 BAR0Size = '128kB' + wb_delay = Param.Latency('10ns', "delay before desc writeback occurs") + fetch_delay = Param.Latency('10ns', "delay before desc fetch occurs") + fetch_comp_delay = Param.Latency('10ns', "delay after desc fetch occurs") + wb_comp_delay = Param.Latency('10ns', "delay after desc wb occurs") + tx_read_delay = Param.Latency('0ns', "delay after tx dma read") + rx_write_delay = Param.Latency('0ns', "delay after rx dma read") + class EtherDevBase(EtherDevice): type = 'EtherDevBase' diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index 98040a252..ca60d2e7d 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -57,7 +57,11 @@ using namespace Net; IGbE::IGbE(const Params *p) : EtherDevice(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), rxDmaPacket(false), rdtrEvent(this), radvEvent(this), + txTick(false), txFifoTick(false), rxDmaPacket(false), + fetchDelay(p->fetch_delay), wbDelay(p->wb_delay), + fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay), + rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay), + 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), @@ -714,7 +718,7 @@ IGbE::RxDescCache::writePacket(EthPacketPtr packet) pktPtr = packet; pktDone = false; igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf), - packet->length, &pktEvent, packet->data); + packet->length, &pktEvent, packet->data, igbe->rxWriteDelay); } void @@ -932,7 +936,7 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p) DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length); igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), - TxdOp::getLen(desc), &pktEvent, p->data + p->length); + TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay); } diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index de73eda79..66a93a509 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -83,6 +83,11 @@ class IGbE : public EtherDevice bool rxDmaPacket; + // Delays in managaging descriptors + Tick fetchDelay, wbDelay; + Tick fetchCompDelay, wbCompDelay; + Tick rxWriteDelay, txReadDelay; + // Event and function to deal with RDTR timer expiring void rdtrProcess() { rxDescCache.writeback(0); @@ -217,7 +222,8 @@ class IGbE : public EtherDevice public: DescCache(IGbE *i, const std::string n, int s) : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0), - pktPtr(NULL), fetchEvent(this), wbEvent(this) + pktPtr(NULL), wbDelayEvent(this), fetchDelayEvent(this), + fetchEvent(this), wbEvent(this) { fetchBuf = new T[size]; wbBuf = new T[size]; @@ -243,6 +249,21 @@ class IGbE : public EtherDevice } void writeback(Addr aMask) + { + if (wbOut) { + if (aMask < wbAlignment) { + moreToWb = true; + wbAlignment = aMask; + } + return; + } + + wbAlignment = aMask; + if (!wbDelayEvent.scheduled()) + wbDelayEvent.schedule(igbe->wbDelay + curTick); + } + + void writeback1() { int curHead = descHead(); int max_to_wb = usedCache.size(); @@ -252,26 +273,13 @@ class IGbE : public EtherDevice curHead, descTail(), descLen(), cachePnt, max_to_wb, descLeft()); - // Check if this writeback is less restrictive that the previous - // and if so setup another one immediately following it - if (wbOut && (aMask < wbAlignment)) { - moreToWb = true; - wbAlignment = aMask; - DPRINTF(EthernetDesc, "Writing back already in process, returning\n"); - return; - } - - - moreToWb = false; - wbAlignment = aMask; - if (max_to_wb + curHead >= descLen()) { max_to_wb = descLen() - curHead; moreToWb = true; // this is by definition aligned correctly - } else if (aMask != 0) { + } else if (wbAlignment != 0) { // align the wb point to the mask - max_to_wb = max_to_wb & ~aMask; + max_to_wb = max_to_wb & ~wbAlignment; } DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb); @@ -291,13 +299,22 @@ class IGbE : public EtherDevice assert(wbOut); igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)), - wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf); + wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf, + igbe->wbCompDelay); } + EventWrapper wbDelayEvent; /** Fetch a chunk of descriptors into the descriptor cache. * Calls fetchComplete when the memory system returns the data */ + void fetchDescriptors() + { + if (!fetchDelayEvent.scheduled()) + fetchDelayEvent.schedule(igbe->fetchDelay + curTick); + } + + void fetchDescriptors1() { size_t max_to_fetch; @@ -331,9 +348,11 @@ class IGbE : public EtherDevice curFetching * sizeof(T)); assert(curFetching); igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)), - curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf); + curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf, + igbe->fetchCompDelay); } + EventWrapper fetchDelayEvent; /** Called by event when dma to read descriptors is completed */ @@ -391,6 +410,7 @@ class IGbE : public EtherDevice // If we still have more to wb, call wb now intAfterWb(); if (moreToWb) { + moreToWb = false; DPRINTF(EthernetDesc, "Writeback has more todo\n"); writeback(wbAlignment); } @@ -463,6 +483,16 @@ class IGbE : public EtherDevice arrayParamOut(os, csprintf("unusedCache_%d", x), (uint8_t*)unusedCache[x],sizeof(T)); } + + Tick fetch_delay = 0, wb_delay = 0; + if (fetchDelayEvent.scheduled()) + fetch_delay = fetchDelayEvent.when(); + SERIALIZE_SCALAR(fetch_delay); + if (wbDelayEvent.scheduled()) + wb_delay = wbDelayEvent.when(); + SERIALIZE_SCALAR(wb_delay); + + } virtual void unserialize(Checkpoint *cp, const std::string §ion) @@ -491,6 +521,15 @@ class IGbE : public EtherDevice (uint8_t*)temp,sizeof(T)); unusedCache.push_back(temp); } + Tick fetch_delay = 0, wb_delay = 0; + UNSERIALIZE_SCALAR(fetch_delay); + UNSERIALIZE_SCALAR(wb_delay); + if (fetch_delay) + fetchDelayEvent.schedule(fetch_delay); + if (wb_delay) + wbDelayEvent.schedule(wb_delay); + + } virtual bool hasOutstandingEvents() { return wbEvent.scheduled() || fetchEvent.scheduled();