X86: Make the real time clock actually keep track of time.
[gem5.git] / src / dev / i8254xGBe.hh
index 4c3896e36c57b1c198de72607e6557111b51155d..f7f7d9a2adaa03acb9bc7e5eda60912bb0bbd53f 100644 (file)
@@ -38,6 +38,7 @@
 #include <deque>
 #include <string>
 
+#include "base/cp_annotate.hh"
 #include "base/inet.hh"
 #include "dev/etherdevice.hh"
 #include "dev/etherint.hh"
@@ -54,6 +55,7 @@ class IGbE : public EtherDevice
 {
   private:
     IGbEInt *etherInt;
+    CPA *cpa;
 
     // device registers
     iGbReg::Regs regs;
@@ -83,6 +85,9 @@ class IGbE : public EtherDevice
 
     bool rxDmaPacket;
 
+    // Number of bytes copied from current RX packet
+    unsigned pktOffset;
+
     // Delays in managaging descriptors
     Tick fetchDelay, wbDelay;
     Tick fetchCompDelay, wbCompDelay;
@@ -91,7 +96,8 @@ class IGbE : public EtherDevice
     // Event and function to deal with RDTR timer expiring
     void rdtrProcess() {
         rxDescCache.writeback(0);
-        DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n");
+        DPRINTF(EthernetIntr,
+                "Posting RXT interrupt because RDTR timer expired\n");
         postInterrupt(iGbReg::IT_RXT);
     }
 
@@ -101,7 +107,8 @@ class IGbE : public EtherDevice
     // Event and function to deal with RADV timer expiring
     void radvProcess() {
         rxDescCache.writeback(0);
-        DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n");
+        DPRINTF(EthernetIntr,
+                "Posting RXT interrupt because RADV timer expired\n");
         postInterrupt(iGbReg::IT_RXT);
     }
 
@@ -111,7 +118,8 @@ class IGbE : public EtherDevice
     // Event and function to deal with TADV timer expiring
     void tadvProcess() {
         txDescCache.writeback(0);
-        DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n");
+        DPRINTF(EthernetIntr,
+                "Posting TXDW interrupt because TADV timer expired\n");
         postInterrupt(iGbReg::IT_TXDW);
     }
 
@@ -121,7 +129,8 @@ class IGbE : public EtherDevice
     // Event and function to deal with TIDV timer expiring
     void tidvProcess() {
         txDescCache.writeback(0);
-        DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n");
+        DPRINTF(EthernetIntr,
+                "Posting TXDW interrupt because TIDV timer expired\n");
         postInterrupt(iGbReg::IT_TXDW);
     }
     //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
@@ -173,6 +182,35 @@ class IGbE : public EtherDevice
      */
     void checkDrain();
 
+    void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) {
+        cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st);
+    }
+
+    void anQ(std::string sm, std::string q) { 
+        cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+    }
+
+    void anDq(std::string sm, std::string q) {
+        cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+    }
+
+    void anPq(std::string sm, std::string q, int num = 1) {
+        cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
+    }
+
+    void anRq(std::string sm, std::string q, int num = 1) {
+        cpa->hwRq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
+    }
+
+    void anWe(std::string sm, std::string q) {
+        cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+    }
+
+    void anWf(std::string sm, std::string q) {
+        cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+    }
+
+
     template<class T>
     class DescCache
     {
@@ -183,11 +221,12 @@ class IGbE : public EtherDevice
         virtual long descLen() const = 0;
         virtual void updateHead(long h) = 0;
         virtual void enableSm() = 0;
-        virtual void intAfterWb() const {}
+        virtual void actionAfterWb() {}
         virtual void fetchAfterWb() = 0;
 
-        std::deque<T*> usedCache;
-        std::deque<T*> unusedCache;
+        typedef std::deque<T *> CacheType;
+        CacheType usedCache;
+        CacheType unusedCache;
 
         T *fetchBuf;
         T *wbBuf;
@@ -217,24 +256,19 @@ class IGbE : public EtherDevice
         // What the alignment is of the next descriptor writeback
         Addr wbAlignment;
 
-       /** The packet that is currently being dmad to memory if any
-         */
+        /** The packet that is currently being dmad to memory if any */
         EthPacketPtr pktPtr;
 
+        /** Shortcut for DMA address translation */
+        Addr pciToDma(Addr a) { return igbe->platform->pciToDma(a); }
+
       public:
-        DescCache(IGbE *i, const std::string n, int s)
-            : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0),
-              pktPtr(NULL), wbDelayEvent(this), fetchDelayEvent(this), 
-              fetchEvent(this), wbEvent(this)
-        {
-            fetchBuf = new T[size];
-            wbBuf = new T[size];
-        }
+        /** Annotate sm*/
+        std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
+            annUsedDescQ, annUnusedCacheQ, annDescQ;
 
-        virtual ~DescCache()
-        {
-            reset();
-        }
+        DescCache(IGbE *i, const std::string n, int s);
+        virtual ~DescCache();
 
         std::string name() { return _name; }
 
@@ -242,228 +276,38 @@ class IGbE : public EtherDevice
          * dirty that is very bad. This function checks that we don't and if we
          * do panics.
          */
-        void areaChanged()
-        {
-            if (usedCache.size() > 0 || curFetching || wbOut)
-                panic("Descriptor Address, Length or Head changed. Bad\n");
-            reset();
-
-        }
+        void areaChanged();
 
-        void writeback(Addr aMask)
-        {
-            int curHead = descHead();
-            int max_to_wb = usedCache.size();
-
-            // Check if this writeback is less restrictive that the previous
-            // and if so setup another one immediately following it
-            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 (wbAlignment != 0) {
-                // align the wb point to the mask
-                max_to_wb = max_to_wb & ~wbAlignment;
-            }
-
-            DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
-
-            if (max_to_wb <= 0) {
-                return;
-            }
-
-            wbOut = max_to_wb;
-
-            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() + descHead() * sizeof(T)),
-                    wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
-                    igbe->wbCompDelay);
-        }
+        void writeback(Addr aMask);
+        void writeback1();
         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;
-
-            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",
-                    descHead(), descTail(), descLen(), cachePnt,
-                    max_to_fetch, descLeft());
-
-            // 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());
-            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,
-                    igbe->fetchCompDelay);
-        }
-
+        void fetchDescriptors();
+        void fetchDescriptors1();
         EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
 
         /** Called by event when dma to read descriptors is completed
          */
-        void fetchComplete()
-        {
-            T *newDesc;
-            for (int x = 0; x < curFetching; x++) {
-                newDesc = new T;
-                memcpy(newDesc, &fetchBuf[x], sizeof(T));
-                unusedCache.push_back(newDesc);
-            }
-
-
-#ifndef NDEBUG
-            int oldCp = cachePnt;
-#endif
-
-            cachePnt += curFetching;
-            assert(cachePnt <= descLen());
-            if (cachePnt == descLen())
-                cachePnt = 0;
-
-            curFetching = 0;
-
-            DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
-                    oldCp, cachePnt);
-
-            enableSm();
-            igbe->checkDrain();
-        }
-
+        void fetchComplete();
         EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
 
         /** Called by event when dma to writeback descriptors is completed
          */
-        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;
-
-            if (curHead >= descLen())
-                curHead -= descLen();
-
-            // Update the head
-            updateHead(curHead);
-
-            DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
-                    oldHead, curHead);
-
-            // If we still have more to wb, call wb now
-            intAfterWb();
-            if (moreToWb) {
-                moreToWb = false;
-                DPRINTF(EthernetDesc, "Writeback has more todo\n");
-                writeback(wbAlignment);
-            }
-
-            if (!wbOut) {
-                igbe->checkDrain();
-            }
-            fetchAfterWb();
-        }
-
-
+        void wbComplete();
         EventWrapper<DescCache, &DescCache::wbComplete> wbEvent;
 
         /* Return the number of descriptors left in the ring, so the device has
          * a way to figure out if it needs to interrupt.
          */
-        int descLeft() const
+        unsigned
+        descLeft() const
         {
-            int left = unusedCache.size();
-            if (cachePnt - descTail() >= 0)
-                left += (cachePnt - descTail());
+            unsigned left = unusedCache.size();
+            if (cachePnt > descTail())
+                left += (descLen() - cachePnt + descTail());
             else
                 left += (descTail() - cachePnt);
 
@@ -472,102 +316,23 @@ class IGbE : public EtherDevice
 
         /* Return the number of descriptors used and not written back.
          */
-        int descUsed() const { return usedCache.size(); }
+        unsigned descUsed() const { return usedCache.size(); }
 
         /* Return the number of cache unused descriptors we have. */
-        int descUnused() const {return unusedCache.size(); }
+        unsigned descUnused() const { return unusedCache.size(); }
 
         /* Get into a state where the descriptor address/head/etc colud be
          * changed */
-        void reset()
-        {
-            DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
-            for (int x = 0; x < usedCache.size(); x++)
-                delete usedCache[x];
-            for (int x = 0; x < unusedCache.size(); x++)
-                delete unusedCache[x];
-
-            usedCache.clear();
-            unusedCache.clear();
-
-            cachePnt = 0;
-
-        }
-
-        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));
-            }
-
-            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)
-        {
-            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);
-            }
-            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);
+        void reset();
 
+        virtual void serialize(std::ostream &os);
+        virtual void unserialize(Checkpoint *cp, const std::string &section);
 
-        }
         virtual bool hasOutstandingEvents() {
             return wbEvent.scheduled() || fetchEvent.scheduled();
         }
 
-     };
+    };
 
 
     class RxDescCache : public DescCache<iGbReg::RxDesc>
@@ -586,6 +351,13 @@ class IGbE : public EtherDevice
 
         bool pktDone;
 
+        /** Variable to head with header/data completion events */
+        int splitCount;
+
+        /** Bytes of packet that have been copied, so we know when to
+            set EOP */
+        unsigned bytesCopied;
+
       public:
         RxDescCache(IGbE *i, std::string n, int s);
 
@@ -593,20 +365,28 @@ class IGbE : public EtherDevice
          * descriptor and update the book keeping. Should only be called when
          * there are no dma's pending.
          * @param packet ethernet packet to write
-         * @return if the packet could be written (there was a free descriptor)
+         * @param pkt_offset bytes already copied from the packet to memory
+         * @return pkt_offset + number of bytes copied during this call
          */
-        void writePacket(EthPacketPtr packet);
+        int writePacket(EthPacketPtr packet, int pkt_offset);
+
         /** Called by event when dma to write packet is completed
          */
         void pktComplete();
 
-        /** Check if the dma on the packet has completed.
+        /** Check if the dma on the packet has completed and RX state machine
+         * can continue
          */
-
         bool packetDone();
 
         EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
 
+        // Event to handle issuing header and data write at the same time
+        // and only callking pktComplete() when both are completed
+        void pktSplitDone();
+        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent;
+        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent;
+
         virtual bool hasOutstandingEvents();
 
         virtual void serialize(std::ostream &os);
@@ -625,16 +405,37 @@ 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 actionAfterWb();
         virtual void fetchAfterWb() {
             if (!igbe->txTick && igbe->getState() == SimObject::Running)
                 fetchDescriptors();
         }
+        
+
 
         bool pktDone;
         bool isTcp;
         bool pktWaiting;
         bool pktMultiDesc;
+        Addr completionAddress;
+        bool completionEnabled;
+        uint32_t descEnd;
+        
+
+        // tso variables
+        bool useTso;
+        Addr tsoHeaderLen;
+        Addr tsoMss;
+        Addr tsoTotalLen;
+        Addr tsoUsedLen;
+        Addr tsoPrevSeq;;
+        Addr tsoPktPayloadBytes;
+        bool tsoLoadedHeader;
+        bool tsoPktHasHeader;
+        uint8_t tsoHeader[256];
+        Addr tsoDescBytesUsed;
+        Addr tsoCopyBytes;
+        int tsoPkts;
 
       public:
         TxDescCache(IGbE *i, std::string n, int s);
@@ -643,8 +444,18 @@ class IGbE : public EtherDevice
          * return the size the of the packet to reserve space in tx fifo.
          * @return size of the packet
          */
-        int getPacketSize();
+        unsigned getPacketSize(EthPacketPtr p);
         void getPacketData(EthPacketPtr p);
+        void processContextDesc();
+
+        /** Return the number of dsecriptors in a cache block for threshold
+         * operations.
+         */
+        unsigned
+        descInBlock(unsigned num_desc)
+        {
+            return num_desc / igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc);
+        }
 
         /** Ask if the packet has been transfered so the state machine can give
          * it to the fifo.
@@ -670,8 +481,25 @@ class IGbE : public EtherDevice
         void pktComplete();
         EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
 
+        void headerComplete();
+        EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
+
+
+        void completionWriteback(Addr a, bool enabled) {
+            DPRINTF(EthernetDesc,
+                    "Completion writeback Addr: %#x enabled: %d\n", 
+                    a, enabled);
+            completionAddress = a;
+            completionEnabled = enabled;
+        }
+
         virtual bool hasOutstandingEvents();
 
+        void nullCallback() {
+            DPRINTF(EthernetDesc, "Completion writeback complete\n");
+        }
+        EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
+
         virtual void serialize(std::ostream &os);
         virtual void unserialize(Checkpoint *cp, const std::string &section);
 
@@ -683,12 +511,13 @@ class IGbE : public EtherDevice
   public:
     typedef IGbEParams Params;
     const Params *
-    params() const
-    {
+    params() const {
         return dynamic_cast<const Params *>(_params);
     }
+
     IGbE(const Params *params);
     ~IGbE() {}
+    virtual void init();
 
     virtual EtherInt *getEthPort(const std::string &if_name, int idx);
 
@@ -725,9 +554,4 @@ class IGbEInt : public EtherInt
     virtual void sendDone() { dev->ethTxDone(); }
 };
 
-
-
-
-
 #endif //__DEV_I8254XGBE_HH__
-