SINIC: Commit old code from ASPLOS 2006 studies.
[gem5.git] / src / dev / i8254xGBe.hh
index cbe7cf8c0856c887c571ff27e9d3787b7d368748..4c3896e36c57b1c198de72607e6557111b51155d 100644 (file)
@@ -39,7 +39,6 @@
 #include <string>
 
 #include "base/inet.hh"
-#include "base/statistics.hh"
 #include "dev/etherdevice.hh"
 #include "dev/etherint.hh"
 #include "dev/etherpkt.hh"
@@ -84,11 +83,16 @@ 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);
         DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n");
-        postInterrupt(iGbReg::IT_RXT, true);
+        postInterrupt(iGbReg::IT_RXT);
     }
 
     //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
@@ -98,7 +102,7 @@ class IGbE : public EtherDevice
     void radvProcess() {
         rxDescCache.writeback(0);
         DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n");
-        postInterrupt(iGbReg::IT_RXT, true);
+        postInterrupt(iGbReg::IT_RXT);
     }
 
     //friend class EventWrapper<IGbE, &IGbE::radvProcess>;
@@ -108,7 +112,7 @@ class IGbE : public EtherDevice
     void tadvProcess() {
         txDescCache.writeback(0);
         DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n");
-        postInterrupt(iGbReg::IT_TXDW, true);
+        postInterrupt(iGbReg::IT_TXDW);
     }
 
     //friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
@@ -118,7 +122,7 @@ class IGbE : public EtherDevice
     void tidvProcess() {
         txDescCache.writeback(0);
         DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n");
-        postInterrupt(iGbReg::IT_TXDW, true);
+        postInterrupt(iGbReg::IT_TXDW);
     }
     //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
     EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
@@ -129,6 +133,8 @@ class IGbE : public EtherDevice
     EventWrapper<IGbE, &IGbE::tick> tickEvent;
 
 
+    uint64_t macAddr;
+
     void rxStateMachine();
     void txStateMachine();
     void txWire();
@@ -218,7 +224,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];
@@ -248,63 +255,93 @@ class IGbE : public EtherDevice
             int curHead = descHead();
             int max_to_wb = usedCache.size();
 
-            DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
-                    "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
-                    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;
+            if (wbOut) {
+                if (aMask < wbAlignment) {
+                    moreToWb = true;
+                    wbAlignment = aMask;
+                }
                 DPRINTF(EthernetDesc, "Writing back already in process, returning\n");
                 return;
             }
 
-
             moreToWb = false;
             wbAlignment = aMask;
+   
+
+            DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
+                    "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
+                    curHead, descTail(), descLen(), cachePnt, max_to_wb,
+                    descLeft());
 
             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);
 
-            if (max_to_wb <= 0 || wbOut)
+            if (max_to_wb <= 0) {
                 return;
+            }
 
             wbOut = max_to_wb;
 
-            for (int x = 0; x < wbOut; x++)
-                memcpy(&wbBuf[x], usedCache[x], sizeof(T));
+            assert(!wbDelayEvent.scheduled()); 
+            wbDelayEvent.schedule(igbe->wbDelay + curTick);
+        }
+            
+        void writeback1()
+        {
+            // If we're draining delay issuing this DMA
+            if (igbe->drainEvent) {
+                wbDelayEvent.schedule(igbe->wbDelay + curTick);
+                return;
+            }
 
+            DPRINTF(EthernetDesc, "Beining DMA of %d descriptors\n", wbOut);
+            
+            for (int x = 0; x < wbOut; x++) {
+                assert(usedCache.size());
+                memcpy(&wbBuf[x], usedCache[x], sizeof(T));
+                 //delete usedCache[0];
+                //usedCache.pop_front();
+            }
 
             assert(wbOut);
-            igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)),
-                    wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf);
+            igbe->dmaWrite(igbe->platform->pciToDma(descBase() + descHead() * sizeof(T)),
+                    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()
         {
             size_t max_to_fetch;
 
+            if (curFetching) {
+                DPRINTF(EthernetDesc, "Currently fetching %d descriptors, returning\n", curFetching);
+                return;
+            }
+
             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()));
+            size_t free_cache = size - usedCache.size() - unusedCache.size();
+
+            max_to_fetch = std::min(max_to_fetch, free_cache);
+            
 
             DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
                     "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
@@ -312,22 +349,35 @@ class IGbE : public EtherDevice
                     max_to_fetch, descLeft());
 
             // Nothing to do
-            if (max_to_fetch == 0 || curFetching)
+            if (max_to_fetch == 0)
                 return;
-
+            
             // So we don't have two descriptor fetches going on at once
             curFetching = max_to_fetch;
 
+            assert(!fetchDelayEvent.scheduled());
+            fetchDelayEvent.schedule(igbe->fetchDelay + curTick);
+        }
+
+        void fetchDescriptors1()
+        {
+            // If we're draining delay issuing this DMA
+            if (igbe->drainEvent) {
+                fetchDelayEvent.schedule(igbe->fetchDelay + curTick);
+                return;
+            }
+
             DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
                     descBase() + cachePnt * sizeof(T),
                     igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
                     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
          */
@@ -340,6 +390,7 @@ class IGbE : public EtherDevice
                 unusedCache.push_back(newDesc);
             }
 
+
 #ifndef NDEBUG
             int oldCp = cachePnt;
 #endif
@@ -369,11 +420,12 @@ class IGbE : public EtherDevice
 #ifndef NDEBUG
             long oldHead = curHead;
 #endif
+            
             for (int x = 0; x < wbOut; x++) {
                 assert(usedCache.size());
                 delete usedCache[0];
                 usedCache.pop_front();
-            };
+            }
 
             curHead += wbOut;
             wbOut = 0;
@@ -390,6 +442,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);
             }
@@ -462,6 +515,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)
@@ -490,6 +553,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();
@@ -523,7 +595,7 @@ class IGbE : public EtherDevice
          * @param packet ethernet packet to write
          * @return if the packet could be written (there was a free descriptor)
          */
-        bool writePacket(EthPacketPtr packet);
+        void writePacket(EthPacketPtr packet);
         /** Called by event when dma to write packet is completed
          */
         void pktComplete();
@@ -553,9 +625,7 @@ class IGbE : public EtherDevice
         virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
         virtual void updateHead(long h) { igbe->regs.tdh(h); }
         virtual void enableSm();
-        virtual void intAfterWb() const {
-            igbe->postInterrupt(iGbReg::IT_TXDW);
-        }
+        virtual void intAfterWb() const { igbe->postInterrupt(iGbReg::IT_TXDW); }
         virtual void fetchAfterWb() {
             if (!igbe->txTick && igbe->getState() == SimObject::Running)
                 fetchDescriptors();
@@ -564,6 +634,7 @@ class IGbE : public EtherDevice
         bool pktDone;
         bool isTcp;
         bool pktWaiting;
+        bool pktMultiDesc;
 
       public:
         TxDescCache(IGbE *i, std::string n, int s);
@@ -586,6 +657,14 @@ class IGbE : public EtherDevice
          */
         bool packetWaiting() { return pktWaiting; }
 
+        /** Ask if this packet is composed of multiple descriptors
+         * so even if we've got data, we need to wait for more before
+         * we can send it out.
+         * @return packet can't be sent out because it's a multi-descriptor
+         * packet
+         */
+        bool packetMultiDesc() { return pktMultiDesc;}
+
         /** Called by event when dma to write packet is completed
          */
         void pktComplete();
@@ -614,7 +693,8 @@ class IGbE : public EtherDevice
     virtual EtherInt *getEthPort(const std::string &if_name, int idx);
 
     Tick clock;
-    inline Tick cycles(int numCycles) const { return numCycles * clock; }
+    Tick lastInterrupt;
+    inline Tick ticks(int numCycles) const { return numCycles * clock; }
 
     virtual Tick read(PacketPtr pkt);
     virtual Tick write(PacketPtr pkt);