Merge in bus DPRINTF changes.
[gem5.git] / src / dev / i8254xGBe.hh
index 3304f0862a57f3a00166b0926243563b486f71cc..30aa6430e9de593e46c73699bdde3a38b702c1ea 100644 (file)
 
 #include "base/inet.hh"
 #include "base/statistics.hh"
+#include "dev/etherdevice.hh"
 #include "dev/etherint.hh"
 #include "dev/etherpkt.hh"
 #include "dev/i8254xGBe_defs.hh"
 #include "dev/pcidev.hh"
 #include "dev/pktfifo.hh"
+#include "params/IGbE.hh"
 #include "sim/eventq.hh"
 
 class IGbEInt;
 
-class IGbE : public PciDev
+class IGbE : public EtherDevice
 {
   private:
     IGbEInt *etherInt;
@@ -62,8 +64,10 @@ class IGbE : public PciDev
     uint8_t eeOpcode, eeAddr;
     uint16_t flash[iGbReg::EEPROM_SIZE];
 
+    // The drain event if we have one
+    Event *drainEvent;
+
     // cached parameters from params struct
-    Tick tickRate;
     bool useFlowControl;
 
     // packet fifos
@@ -78,6 +82,8 @@ class IGbE : public PciDev
     bool txTick;
     bool txFifoTick;
 
+    bool rxDmaPacket;
+
     // Event and function to deal with RDTR timer expiring
     void rdtrProcess() {
         rxDescCache.writeback(0);
@@ -141,9 +147,10 @@ class IGbE : public PciDev
 
     /** Send an interrupt to the cpu
      */
+    void delayIntEvent();
     void cpuPostInt();
     // Event to moderate interrupts
-    EventWrapper<IGbE, &IGbE::cpuPostInt> interEvent;
+    EventWrapper<IGbE, &IGbE::delayIntEvent> interEvent;
 
     /** Clear the interupt line to the cpu
      */
@@ -151,8 +158,15 @@ class IGbE : public PciDev
 
     Tick intClock() { return Clock::Int::ns * 1024; }
 
+    /** This function is used to restart the clock so it can handle things like
+     * draining and resume in one place. */
     void restartClock();
 
+    /** Check if all the draining things that need to occur have occured and
+     * handle the drain event if so.
+     */
+    void checkDrain();
+
     template<class T>
     class DescCache
     {
@@ -164,6 +178,7 @@ class IGbE : public PciDev
         virtual void updateHead(long h) = 0;
         virtual void enableSm() = 0;
         virtual void intAfterWb() const {}
+        virtual void fetchAfterWb() = 0;
 
         std::deque<T*> usedCache;
         std::deque<T*> unusedCache;
@@ -270,12 +285,6 @@ class IGbE : public PciDev
             for (int x = 0; x < wbOut; x++)
                 memcpy(&wbBuf[x], usedCache[x], sizeof(T));
 
-            for (int x = 0; x < wbOut; x++) {
-                assert(usedCache.size());
-                delete usedCache[0];
-                usedCache.pop_front();
-            };
-
 
             assert(wbOut);
             igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)),
@@ -294,7 +303,6 @@ class IGbE : public PciDev
             else
                 max_to_fetch = descLen() - cachePnt;
 
-
             max_to_fetch = std::min(max_to_fetch, (size - usedCache.size() -
                         unusedCache.size()));
 
@@ -347,7 +355,7 @@ class IGbE : public PciDev
                     oldCp, cachePnt);
 
             enableSm();
-
+            igbe->checkDrain();
         }
 
         EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
@@ -356,10 +364,16 @@ class IGbE : public PciDev
          */
         void wbComplete()
         {
+
             long  curHead = descHead();
 #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;
@@ -374,11 +388,16 @@ class IGbE : public PciDev
                     oldHead, curHead);
 
             // If we still have more to wb, call wb now
+            intAfterWb();
             if (moreToWb) {
                 DPRINTF(EthernetDesc, "Writeback has more todo\n");
                 writeback(wbAlignment);
             }
-            intAfterWb();
+
+            if (!wbOut) {
+                igbe->checkDrain();
+            }
+            fetchAfterWb();
         }
 
 
@@ -422,6 +441,60 @@ class IGbE : public PciDev
 
         }
 
+        virtual void serialize(std::ostream &os)
+        {
+            SERIALIZE_SCALAR(cachePnt);
+            SERIALIZE_SCALAR(curFetching);
+            SERIALIZE_SCALAR(wbOut);
+            SERIALIZE_SCALAR(moreToWb);
+            SERIALIZE_SCALAR(wbAlignment);
+
+            int usedCacheSize = usedCache.size();
+            SERIALIZE_SCALAR(usedCacheSize);
+            for(int x = 0; x < usedCacheSize; x++) {
+                arrayParamOut(os, csprintf("usedCache_%d", x),
+                        (uint8_t*)usedCache[x],sizeof(T));
+            }
+
+            int unusedCacheSize = unusedCache.size();
+            SERIALIZE_SCALAR(unusedCacheSize);
+            for(int x = 0; x < unusedCacheSize; x++) {
+                arrayParamOut(os, csprintf("unusedCache_%d", x),
+                        (uint8_t*)unusedCache[x],sizeof(T));
+            }
+        }
+
+        virtual void unserialize(Checkpoint *cp, const std::string &section)
+        {
+            UNSERIALIZE_SCALAR(cachePnt);
+            UNSERIALIZE_SCALAR(curFetching);
+            UNSERIALIZE_SCALAR(wbOut);
+            UNSERIALIZE_SCALAR(moreToWb);
+            UNSERIALIZE_SCALAR(wbAlignment);
+
+            int usedCacheSize;
+            UNSERIALIZE_SCALAR(usedCacheSize);
+            T *temp;
+            for(int x = 0; x < usedCacheSize; x++) {
+                temp = new T;
+                arrayParamIn(cp, section, csprintf("usedCache_%d", x),
+                        (uint8_t*)temp,sizeof(T));
+                usedCache.push_back(temp);
+            }
+
+            int unusedCacheSize;
+            UNSERIALIZE_SCALAR(unusedCacheSize);
+            for(int x = 0; x < unusedCacheSize; x++) {
+                temp = new T;
+                arrayParamIn(cp, section, csprintf("unusedCache_%d", x),
+                        (uint8_t*)temp,sizeof(T));
+                unusedCache.push_back(temp);
+            }
+        }
+        virtual bool hasOutstandingEvents() {
+            return wbEvent.scheduled() || fetchEvent.scheduled();
+        }
+
      };
 
 
@@ -434,6 +507,10 @@ class IGbE : public PciDev
         virtual long descTail() const { return igbe->regs.rdt(); }
         virtual void updateHead(long h) { igbe->regs.rdh(h); }
         virtual void enableSm();
+        virtual void fetchAfterWb() {
+            if (!igbe->rxTick && igbe->getState() == SimObject::Running)
+                fetchDescriptors();
+        }
 
         bool pktDone;
 
@@ -458,6 +535,10 @@ class IGbE : public PciDev
 
         EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
 
+        virtual bool hasOutstandingEvents();
+
+        virtual void serialize(std::ostream &os);
+        virtual void unserialize(Checkpoint *cp, const std::string &section);
     };
     friend class RxDescCache;
 
@@ -472,12 +553,17 @@ class IGbE : public PciDev
         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();
+        }
 
         bool pktDone;
         bool isTcp;
         bool pktWaiting;
-        int hLen;
 
       public:
         TxDescCache(IGbE *i, std::string n, int s);
@@ -505,28 +591,30 @@ class IGbE : public PciDev
         void pktComplete();
         EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
 
+        virtual bool hasOutstandingEvents();
+
+        virtual void serialize(std::ostream &os);
+        virtual void unserialize(Checkpoint *cp, const std::string &section);
+
     };
     friend class TxDescCache;
 
     TxDescCache txDescCache;
 
   public:
-    struct Params : public PciDev::Params
+    typedef IGbEParams Params;
+    const Params *
+    params() const
     {
-        Net::EthAddr hardware_address;
-        bool use_flow_control;
-        int rx_fifo_size;
-        int tx_fifo_size;
-        int rx_desc_cache_size;
-        int tx_desc_cache_size;
-        Tick clock;
-    };
+        return dynamic_cast<const Params *>(_params);
+    }
+    IGbE(const Params *params);
+    ~IGbE() {}
 
-    IGbE(Params *params);
-    ~IGbE() {;}
+    virtual EtherInt *getEthPort(const std::string &if_name, int idx);
 
     Tick clock;
-    inline Tick cycles(int numCycles) const { return numCycles * clock; }
+    inline Tick ticks(int numCycles) const { return numCycles * clock; }
 
     virtual Tick read(PacketPtr pkt);
     virtual Tick write(PacketPtr pkt);
@@ -536,14 +624,10 @@ class IGbE : public PciDev
     bool ethRxPkt(EthPacketPtr packet);
     void ethTxDone();
 
-    void setEthInt(IGbEInt *i) { assert(!etherInt); etherInt = i; }
-
-
-    const Params *params() const {return (const Params *)_params; }
-
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
-
+    virtual unsigned int drain(Event *de);
+    virtual void resume();
 
 };
 
@@ -555,7 +639,7 @@ class IGbEInt : public EtherInt
   public:
     IGbEInt(const std::string &name, IGbE *d)
         : EtherInt(name), dev(d)
-        { dev->setEthInt(this); }
+    { }
 
     virtual bool recvPacket(EthPacketPtr pkt) { return dev->ethRxPkt(pkt); }
     virtual void sendDone() { dev->ethTxDone(); }