Add the ability to specify a think time before descriptor fetch/writeback starts...
authorAli Saidi <saidi@eecs.umich.edu>
Wed, 13 Aug 2008 21:41:58 +0000 (17:41 -0400)
committerAli Saidi <saidi@eecs.umich.edu>
Wed, 13 Aug 2008 21:41:58 +0000 (17:41 -0400)
src/dev/Ethernet.py
src/dev/i8254xGBe.cc
src/dev/i8254xGBe.hh

index 2beb0d5379bbc9f6f18317b10d72079f5a489f06..01384b32bb71c7b3aa190f5fee17daf3c7c7677a 100644 (file)
@@ -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'
index 98040a252a8a505e882870b677a182a159d704de..ca60d2e7de65007a6620982ebbf6f58f0a4d81d5 100644 (file)
@@ -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);
 
 
 }
index de73eda79c86481eef84d1b8d6956082472d70da..66a93a50951cd63b6548e1e08489fbbc68ba6222 100644 (file)
@@ -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<DescCache, &DescCache::writeback1> 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<DescCache, &DescCache::fetchDescriptors1> 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 &section)
@@ -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();