Add the ability to specify a think time before descriptor fetch/writeback starts/ends as well as after read/write dmas

This commit is contained in:
Ali Saidi 2008-08-13 17:41:58 -04:00
parent 549c43b2d0
commit 6248e12704
3 changed files with 71 additions and 21 deletions

View file

@ -98,6 +98,13 @@ class IGbE(EtherDevice):
InterruptLine = 0x1e InterruptLine = 0x1e
InterruptPin = 0x01 InterruptPin = 0x01
BAR0Size = '128kB' 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): class EtherDevBase(EtherDevice):
type = 'EtherDevBase' type = 'EtherDevBase'

View file

@ -57,7 +57,11 @@ using namespace Net;
IGbE::IGbE(const Params *p) IGbE::IGbE(const Params *p)
: EtherDevice(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control), : EtherDevice(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control),
rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), 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), tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size), rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
@ -714,7 +718,7 @@ IGbE::RxDescCache::writePacket(EthPacketPtr packet)
pktPtr = packet; pktPtr = packet;
pktDone = false; pktDone = false;
igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf), igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
packet->length, &pktEvent, packet->data); packet->length, &pktEvent, packet->data, igbe->rxWriteDelay);
} }
void void
@ -932,7 +936,7 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p)
DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length); DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), 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);
} }

View file

@ -83,6 +83,11 @@ class IGbE : public EtherDevice
bool rxDmaPacket; bool rxDmaPacket;
// Delays in managaging descriptors
Tick fetchDelay, wbDelay;
Tick fetchCompDelay, wbCompDelay;
Tick rxWriteDelay, txReadDelay;
// Event and function to deal with RDTR timer expiring // Event and function to deal with RDTR timer expiring
void rdtrProcess() { void rdtrProcess() {
rxDescCache.writeback(0); rxDescCache.writeback(0);
@ -217,7 +222,8 @@ class IGbE : public EtherDevice
public: public:
DescCache(IGbE *i, const std::string n, int s) DescCache(IGbE *i, const std::string n, int s)
: igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0), : 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]; fetchBuf = new T[size];
wbBuf = new T[size]; wbBuf = new T[size];
@ -243,6 +249,21 @@ class IGbE : public EtherDevice
} }
void writeback(Addr aMask) 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 curHead = descHead();
int max_to_wb = usedCache.size(); int max_to_wb = usedCache.size();
@ -252,26 +273,13 @@ class IGbE : public EtherDevice
curHead, descTail(), descLen(), cachePnt, max_to_wb, curHead, descTail(), descLen(), cachePnt, max_to_wb,
descLeft()); 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()) { if (max_to_wb + curHead >= descLen()) {
max_to_wb = descLen() - curHead; max_to_wb = descLen() - curHead;
moreToWb = true; moreToWb = true;
// this is by definition aligned correctly // this is by definition aligned correctly
} else if (aMask != 0) { } else if (wbAlignment != 0) {
// align the wb point to the mask // 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); DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
@ -291,13 +299,22 @@ class IGbE : public EtherDevice
assert(wbOut); assert(wbOut);
igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)), 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<DescCache, &DescCache::writeback1> wbDelayEvent;
/** Fetch a chunk of descriptors into the descriptor cache. /** Fetch a chunk of descriptors into the descriptor cache.
* Calls fetchComplete when the memory system returns the data * Calls fetchComplete when the memory system returns the data
*/ */
void fetchDescriptors() void fetchDescriptors()
{
if (!fetchDelayEvent.scheduled())
fetchDelayEvent.schedule(igbe->fetchDelay + curTick);
}
void fetchDescriptors1()
{ {
size_t max_to_fetch; size_t max_to_fetch;
@ -331,9 +348,11 @@ class IGbE : public EtherDevice
curFetching * sizeof(T)); curFetching * sizeof(T));
assert(curFetching); assert(curFetching);
igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)), 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<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
/** Called by event when dma to read descriptors is completed /** 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 // If we still have more to wb, call wb now
intAfterWb(); intAfterWb();
if (moreToWb) { if (moreToWb) {
moreToWb = false;
DPRINTF(EthernetDesc, "Writeback has more todo\n"); DPRINTF(EthernetDesc, "Writeback has more todo\n");
writeback(wbAlignment); writeback(wbAlignment);
} }
@ -463,6 +483,16 @@ class IGbE : public EtherDevice
arrayParamOut(os, csprintf("unusedCache_%d", x), arrayParamOut(os, csprintf("unusedCache_%d", x),
(uint8_t*)unusedCache[x],sizeof(T)); (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 &section) virtual void unserialize(Checkpoint *cp, const std::string &section)
@ -491,6 +521,15 @@ class IGbE : public EtherDevice
(uint8_t*)temp,sizeof(T)); (uint8_t*)temp,sizeof(T));
unusedCache.push_back(temp); 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() { virtual bool hasOutstandingEvents() {
return wbEvent.scheduled() || fetchEvent.scheduled(); return wbEvent.scheduled() || fetchEvent.scheduled();