SimObjects: Clean up handling of C++ namespaces.
[gem5.git] / src / dev / i8254xGBe.hh
index 9403c87b62dcd30827903687a7d2a97ff43a8697..618145d07a5ceb5a12203de9f5eb2e86e280fdf3 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,62 +255,83 @@ 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;
 
+            assert(!wbDelayEvent.scheduled()); 
+            igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
+        }
+            
+        void writeback1()
+        {
+            // If we're draining delay issuing this DMA
+            if (igbe->drainEvent) {
+                igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
+                return;
+            }
+
+            DPRINTF(EthernetDesc, "Beining DMA of %d descriptors\n", wbOut);
+            
             for (int x = 0; x < wbOut; x++) {
                 assert(usedCache.size());
-                memcpy(&wbBuf[x], usedCache[0], sizeof(T));
-                delete usedCache[0];
-                usedCache.pop_front();
+                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)
+            if (curFetching) {
+                DPRINTF(EthernetDesc, "Currently fetching %d descriptors, returning\n", curFetching);
                 return;
+            }
 
             if (descTail() >= cachePnt)
                 max_to_fetch = descTail() - cachePnt;
@@ -313,6 +341,7 @@ class IGbE : public EtherDevice
             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",
@@ -322,19 +351,33 @@ class IGbE : public EtherDevice
             // Nothing to do
             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());
+            igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
+        }
+
+        void fetchDescriptors1()
+        {
+            // If we're draining delay issuing this DMA
+            if (igbe->drainEvent) {
+                igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
+                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
          */
@@ -347,6 +390,7 @@ class IGbE : public EtherDevice
                 unusedCache.push_back(newDesc);
             }
 
+
 #ifndef NDEBUG
             int oldCp = cachePnt;
 #endif
@@ -376,6 +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;
@@ -392,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);
             }
@@ -464,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)
@@ -492,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)
+                igbe->schedule(fetchDelayEvent, fetch_delay);
+            if (wb_delay)
+                igbe->schedule(wbDelayEvent, wb_delay);
+
+
         }
         virtual bool hasOutstandingEvents() {
             return wbEvent.scheduled() || fetchEvent.scheduled();
@@ -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,6 +693,7 @@ class IGbE : public EtherDevice
     virtual EtherInt *getEthPort(const std::string &if_name, int idx);
 
     Tick clock;
+    Tick lastInterrupt;
     inline Tick ticks(int numCycles) const { return numCycles * clock; }
 
     virtual Tick read(PacketPtr pkt);