i8254xGBe.hh revision 5954
15245Sgblack@eecs.umich.edu/*
25245Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
35245Sgblack@eecs.umich.edu * All rights reserved.
45245Sgblack@eecs.umich.edu *
57087Snate@binkert.org * Redistribution and use in source and binary forms, with or without
67087Snate@binkert.org * modification, are permitted provided that the following conditions are
77087Snate@binkert.org * met: redistributions of source code must retain the above copyright
87087Snate@binkert.org * notice, this list of conditions and the following disclaimer;
97087Snate@binkert.org * redistributions in binary form must reproduce the above copyright
107087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
117087Snate@binkert.org * documentation and/or other materials provided with the distribution;
127087Snate@binkert.org * neither the name of the copyright holders nor the names of its
135245Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147087Snate@binkert.org * this software without specific prior written permission.
157087Snate@binkert.org *
167087Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177087Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187087Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197087Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207087Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217087Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225245Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237087Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245245Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255245Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265245Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275245Sgblack@eecs.umich.edu *
285245Sgblack@eecs.umich.edu * Authors: Ali Saidi
295245Sgblack@eecs.umich.edu */
305245Sgblack@eecs.umich.edu
315245Sgblack@eecs.umich.edu/* @file
325245Sgblack@eecs.umich.edu * Device model for Intel's 8254x line of gigabit ethernet controllers.
335245Sgblack@eecs.umich.edu */
345245Sgblack@eecs.umich.edu
355245Sgblack@eecs.umich.edu#ifndef __DEV_I8254XGBE_HH__
365245Sgblack@eecs.umich.edu#define __DEV_I8254XGBE_HH__
375245Sgblack@eecs.umich.edu
385245Sgblack@eecs.umich.edu#include <deque>
395245Sgblack@eecs.umich.edu#include <string>
405245Sgblack@eecs.umich.edu
415245Sgblack@eecs.umich.edu#include "base/cp_annotate.hh"
425245Sgblack@eecs.umich.edu#include "base/inet.hh"
437912Shestness@cs.utexas.edu#include "dev/etherdevice.hh"
445245Sgblack@eecs.umich.edu#include "dev/etherint.hh"
458229Snate@binkert.org#include "dev/etherpkt.hh"
465245Sgblack@eecs.umich.edu#include "dev/i8254xGBe_defs.hh"
478232Snate@binkert.org#include "dev/pcidev.hh"
485245Sgblack@eecs.umich.edu#include "dev/pktfifo.hh"
495245Sgblack@eecs.umich.edu#include "params/IGbE.hh"
505245Sgblack@eecs.umich.edu#include "sim/eventq.hh"
515245Sgblack@eecs.umich.edu
525245Sgblack@eecs.umich.educlass IGbEInt;
535245Sgblack@eecs.umich.edu
545245Sgblack@eecs.umich.educlass IGbE : public EtherDevice
555245Sgblack@eecs.umich.edu{
565245Sgblack@eecs.umich.edu  private:
575245Sgblack@eecs.umich.edu    IGbEInt *etherInt;
585245Sgblack@eecs.umich.edu    CPA *cpa;
595245Sgblack@eecs.umich.edu
605245Sgblack@eecs.umich.edu    // device registers
615245Sgblack@eecs.umich.edu    iGbReg::Regs regs;
625245Sgblack@eecs.umich.edu
635245Sgblack@eecs.umich.edu    // eeprom data, status and control bits
645245Sgblack@eecs.umich.edu    int eeOpBits, eeAddrBits, eeDataBits;
655245Sgblack@eecs.umich.edu    uint8_t eeOpcode, eeAddr;
665245Sgblack@eecs.umich.edu    uint16_t flash[iGbReg::EEPROM_SIZE];
675245Sgblack@eecs.umich.edu
685245Sgblack@eecs.umich.edu    // The drain event if we have one
695245Sgblack@eecs.umich.edu    Event *drainEvent;
705245Sgblack@eecs.umich.edu
715895Sgblack@eecs.umich.edu    // cached parameters from params struct
727912Shestness@cs.utexas.edu    bool useFlowControl;
737912Shestness@cs.utexas.edu
745245Sgblack@eecs.umich.edu    // packet fifos
757912Shestness@cs.utexas.edu    PacketFifo rxFifo;
767912Shestness@cs.utexas.edu    PacketFifo txFifo;
777912Shestness@cs.utexas.edu
787912Shestness@cs.utexas.edu    // Packet that we are currently putting into the txFifo
797912Shestness@cs.utexas.edu    EthPacketPtr txPacket;
807912Shestness@cs.utexas.edu
817912Shestness@cs.utexas.edu    // Should to Rx/Tx State machine tick?
827912Shestness@cs.utexas.edu    bool rxTick;
837912Shestness@cs.utexas.edu    bool txTick;
847912Shestness@cs.utexas.edu    bool txFifoTick;
857912Shestness@cs.utexas.edu
867912Shestness@cs.utexas.edu    bool rxDmaPacket;
877912Shestness@cs.utexas.edu
887912Shestness@cs.utexas.edu    // Number of bytes copied from current RX packet
897912Shestness@cs.utexas.edu    int pktOffset;
907912Shestness@cs.utexas.edu
915895Sgblack@eecs.umich.edu    // Delays in managaging descriptors
927912Shestness@cs.utexas.edu    Tick fetchDelay, wbDelay;
935245Sgblack@eecs.umich.edu    Tick fetchCompDelay, wbCompDelay;
945245Sgblack@eecs.umich.edu    Tick rxWriteDelay, txReadDelay;
955245Sgblack@eecs.umich.edu
965895Sgblack@eecs.umich.edu    // Event and function to deal with RDTR timer expiring
977912Shestness@cs.utexas.edu    void rdtrProcess() {
987912Shestness@cs.utexas.edu        rxDescCache.writeback(0);
995245Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n");
1007912Shestness@cs.utexas.edu        postInterrupt(iGbReg::IT_RXT);
1017912Shestness@cs.utexas.edu    }
1025245Sgblack@eecs.umich.edu
1035245Sgblack@eecs.umich.edu    //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
1045245Sgblack@eecs.umich.edu    EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
1055245Sgblack@eecs.umich.edu
1065245Sgblack@eecs.umich.edu    // Event and function to deal with RADV timer expiring
1075245Sgblack@eecs.umich.edu    void radvProcess() {
1085245Sgblack@eecs.umich.edu        rxDescCache.writeback(0);
1095245Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n");
1105245Sgblack@eecs.umich.edu        postInterrupt(iGbReg::IT_RXT);
1115245Sgblack@eecs.umich.edu    }
1125245Sgblack@eecs.umich.edu
1137912Shestness@cs.utexas.edu    //friend class EventWrapper<IGbE, &IGbE::radvProcess>;
1147912Shestness@cs.utexas.edu    EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
1157912Shestness@cs.utexas.edu
1167912Shestness@cs.utexas.edu    // Event and function to deal with TADV timer expiring
1177912Shestness@cs.utexas.edu    void tadvProcess() {
1187912Shestness@cs.utexas.edu        txDescCache.writeback(0);
1197912Shestness@cs.utexas.edu        DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n");
1207912Shestness@cs.utexas.edu        postInterrupt(iGbReg::IT_TXDW);
1217912Shestness@cs.utexas.edu    }
1227912Shestness@cs.utexas.edu
1237912Shestness@cs.utexas.edu    //friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
1247912Shestness@cs.utexas.edu    EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent;
1257912Shestness@cs.utexas.edu
1267912Shestness@cs.utexas.edu    // Event and function to deal with TIDV timer expiring
1277912Shestness@cs.utexas.edu    void tidvProcess() {
1285245Sgblack@eecs.umich.edu        txDescCache.writeback(0);
1297912Shestness@cs.utexas.edu        DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n");
1307912Shestness@cs.utexas.edu        postInterrupt(iGbReg::IT_TXDW);
1317912Shestness@cs.utexas.edu    }
1327912Shestness@cs.utexas.edu    //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
1337912Shestness@cs.utexas.edu    EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
1347912Shestness@cs.utexas.edu
1357912Shestness@cs.utexas.edu    // Main event to tick the device
1365895Sgblack@eecs.umich.edu    void tick();
1375245Sgblack@eecs.umich.edu    //friend class EventWrapper<IGbE, &IGbE::tick>;
1387912Shestness@cs.utexas.edu    EventWrapper<IGbE, &IGbE::tick> tickEvent;
1397912Shestness@cs.utexas.edu
1405245Sgblack@eecs.umich.edu
1415245Sgblack@eecs.umich.edu    uint64_t macAddr;
1425245Sgblack@eecs.umich.edu
1435245Sgblack@eecs.umich.edu    void rxStateMachine();
1445245Sgblack@eecs.umich.edu    void txStateMachine();
1455245Sgblack@eecs.umich.edu    void txWire();
1465245Sgblack@eecs.umich.edu
1475245Sgblack@eecs.umich.edu    /** Write an interrupt into the interrupt pending register and check mask
1485245Sgblack@eecs.umich.edu     * and interrupt limit timer before sending interrupt to CPU
1495245Sgblack@eecs.umich.edu     * @param t the type of interrupt we are posting
1505245Sgblack@eecs.umich.edu     * @param now should we ignore the interrupt limiting timer
1515245Sgblack@eecs.umich.edu     */
1525245Sgblack@eecs.umich.edu    void postInterrupt(iGbReg::IntTypes t, bool now = false);
1535245Sgblack@eecs.umich.edu
1545245Sgblack@eecs.umich.edu    /** Check and see if changes to the mask register have caused an interrupt
1555245Sgblack@eecs.umich.edu     * to need to be sent or perhaps removed an interrupt cause.
1565245Sgblack@eecs.umich.edu     */
1575245Sgblack@eecs.umich.edu    void chkInterrupt();
1585245Sgblack@eecs.umich.edu
1595245Sgblack@eecs.umich.edu    /** Send an interrupt to the cpu
1605245Sgblack@eecs.umich.edu     */
1615245Sgblack@eecs.umich.edu    void delayIntEvent();
1625245Sgblack@eecs.umich.edu    void cpuPostInt();
1635245Sgblack@eecs.umich.edu    // Event to moderate interrupts
1645245Sgblack@eecs.umich.edu    EventWrapper<IGbE, &IGbE::delayIntEvent> interEvent;
1655245Sgblack@eecs.umich.edu
1665245Sgblack@eecs.umich.edu    /** Clear the interupt line to the cpu
1675245Sgblack@eecs.umich.edu     */
1685245Sgblack@eecs.umich.edu    void cpuClearInt();
1695245Sgblack@eecs.umich.edu
1705245Sgblack@eecs.umich.edu    Tick intClock() { return Clock::Int::ns * 1024; }
1715245Sgblack@eecs.umich.edu
1725245Sgblack@eecs.umich.edu    /** This function is used to restart the clock so it can handle things like
1735245Sgblack@eecs.umich.edu     * draining and resume in one place. */
1745245Sgblack@eecs.umich.edu    void restartClock();
1755245Sgblack@eecs.umich.edu
1765245Sgblack@eecs.umich.edu    /** Check if all the draining things that need to occur have occured and
1775245Sgblack@eecs.umich.edu     * handle the drain event if so.
1785245Sgblack@eecs.umich.edu     */
1797912Shestness@cs.utexas.edu    void checkDrain();
1807912Shestness@cs.utexas.edu
1817912Shestness@cs.utexas.edu    void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) {
1827912Shestness@cs.utexas.edu        cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st);
1837912Shestness@cs.utexas.edu    }
1847912Shestness@cs.utexas.edu
1857912Shestness@cs.utexas.edu    void anQ(std::string sm, std::string q) {
1867912Shestness@cs.utexas.edu        cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
1877912Shestness@cs.utexas.edu    }
1887912Shestness@cs.utexas.edu
1897912Shestness@cs.utexas.edu    void anDq(std::string sm, std::string q) {
1907912Shestness@cs.utexas.edu        cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
1917912Shestness@cs.utexas.edu    }
1927912Shestness@cs.utexas.edu
1937912Shestness@cs.utexas.edu    void anPq(std::string sm, std::string q, int num = 1) {
1947912Shestness@cs.utexas.edu        cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
1957912Shestness@cs.utexas.edu    }
1967912Shestness@cs.utexas.edu
1977912Shestness@cs.utexas.edu    void anRq(std::string sm, std::string q, int num = 1) {
1987912Shestness@cs.utexas.edu        cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
1997912Shestness@cs.utexas.edu    }
2007912Shestness@cs.utexas.edu
2015245Sgblack@eecs.umich.edu    void anWe(std::string sm, std::string q) {
2025245Sgblack@eecs.umich.edu        cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
2035245Sgblack@eecs.umich.edu    }
2047912Shestness@cs.utexas.edu
2057912Shestness@cs.utexas.edu    void anWf(std::string sm, std::string q) {
2067912Shestness@cs.utexas.edu        cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
2077912Shestness@cs.utexas.edu    }
2087912Shestness@cs.utexas.edu
2097912Shestness@cs.utexas.edu
2107912Shestness@cs.utexas.edu    template<class T>
2117912Shestness@cs.utexas.edu    class DescCache
2127912Shestness@cs.utexas.edu    {
2137912Shestness@cs.utexas.edu      protected:
2147912Shestness@cs.utexas.edu        virtual Addr descBase() const = 0;
2157912Shestness@cs.utexas.edu        virtual long descHead() const = 0;
2167912Shestness@cs.utexas.edu        virtual long descTail() const = 0;
2177912Shestness@cs.utexas.edu        virtual long descLen() const = 0;
2187912Shestness@cs.utexas.edu        virtual void updateHead(long h) = 0;
2197912Shestness@cs.utexas.edu        virtual void enableSm() = 0;
2207912Shestness@cs.utexas.edu        virtual void actionAfterWb() {}
2217912Shestness@cs.utexas.edu        virtual void fetchAfterWb() = 0;
2227912Shestness@cs.utexas.edu
2237912Shestness@cs.utexas.edu        std::deque<T*> usedCache;
2247912Shestness@cs.utexas.edu        std::deque<T*> unusedCache;
2257912Shestness@cs.utexas.edu
2267912Shestness@cs.utexas.edu        T *fetchBuf;
2277912Shestness@cs.utexas.edu        T *wbBuf;
2287912Shestness@cs.utexas.edu
2297912Shestness@cs.utexas.edu        // Pointer to the device we cache for
2307912Shestness@cs.utexas.edu        IGbE *igbe;
2317912Shestness@cs.utexas.edu
2327912Shestness@cs.utexas.edu        // Name of this  descriptor cache
2337912Shestness@cs.utexas.edu        std::string _name;
2347912Shestness@cs.utexas.edu
2357912Shestness@cs.utexas.edu        // How far we've cached
2367912Shestness@cs.utexas.edu        int cachePnt;
2377912Shestness@cs.utexas.edu
2387912Shestness@cs.utexas.edu        // The size of the descriptor cache
2397912Shestness@cs.utexas.edu        int size;
2407912Shestness@cs.utexas.edu
2417912Shestness@cs.utexas.edu        // How many descriptors we are currently fetching
2427912Shestness@cs.utexas.edu        int curFetching;
2437912Shestness@cs.utexas.edu
2447912Shestness@cs.utexas.edu        // How many descriptors we are currently writing back
2457912Shestness@cs.utexas.edu        int wbOut;
2467912Shestness@cs.utexas.edu
2477912Shestness@cs.utexas.edu        // if the we wrote back to the end of the descriptor ring and are going
2487912Shestness@cs.utexas.edu        // to have to wrap and write more
2497912Shestness@cs.utexas.edu        bool moreToWb;
2507912Shestness@cs.utexas.edu
2517912Shestness@cs.utexas.edu        // What the alignment is of the next descriptor writeback
2527912Shestness@cs.utexas.edu        Addr wbAlignment;
2537912Shestness@cs.utexas.edu
2547912Shestness@cs.utexas.edu       /** The packet that is currently being dmad to memory if any
2557912Shestness@cs.utexas.edu         */
2567912Shestness@cs.utexas.edu        EthPacketPtr pktPtr;
2577912Shestness@cs.utexas.edu
2587912Shestness@cs.utexas.edu      public:
2597912Shestness@cs.utexas.edu        /** Annotate sm*/
2607912Shestness@cs.utexas.edu        std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
2617912Shestness@cs.utexas.edu            annUsedDescQ, annUnusedCacheQ, annDescQ;
2627912Shestness@cs.utexas.edu
2637912Shestness@cs.utexas.edu        DescCache(IGbE *i, const std::string n, int s)
2647912Shestness@cs.utexas.edu            : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0),
2657912Shestness@cs.utexas.edu              pktPtr(NULL), wbDelayEvent(this), fetchDelayEvent(this),
2667912Shestness@cs.utexas.edu              fetchEvent(this), wbEvent(this)
2677912Shestness@cs.utexas.edu        {
2687912Shestness@cs.utexas.edu            fetchBuf = new T[size];
2697912Shestness@cs.utexas.edu            wbBuf = new T[size];
2707912Shestness@cs.utexas.edu        }
2717912Shestness@cs.utexas.edu
2727912Shestness@cs.utexas.edu        virtual ~DescCache()
2737912Shestness@cs.utexas.edu        {
2747912Shestness@cs.utexas.edu            reset();
2757912Shestness@cs.utexas.edu        }
2767912Shestness@cs.utexas.edu
2777912Shestness@cs.utexas.edu        std::string name() { return _name; }
2787912Shestness@cs.utexas.edu
2797912Shestness@cs.utexas.edu        /** If the address/len/head change when we've got descriptors that are
2807912Shestness@cs.utexas.edu         * dirty that is very bad. This function checks that we don't and if we
2817912Shestness@cs.utexas.edu         * do panics.
2827912Shestness@cs.utexas.edu         */
2837912Shestness@cs.utexas.edu        void areaChanged()
2847912Shestness@cs.utexas.edu        {
2857912Shestness@cs.utexas.edu            if (usedCache.size() > 0 || curFetching || wbOut)
2867912Shestness@cs.utexas.edu                panic("Descriptor Address, Length or Head changed. Bad\n");
2877912Shestness@cs.utexas.edu            reset();
2887912Shestness@cs.utexas.edu
2897912Shestness@cs.utexas.edu        }
2907912Shestness@cs.utexas.edu
2917912Shestness@cs.utexas.edu        void writeback(Addr aMask)
2927912Shestness@cs.utexas.edu        {
2937912Shestness@cs.utexas.edu            int curHead = descHead();
2947912Shestness@cs.utexas.edu            int max_to_wb = usedCache.size();
2957912Shestness@cs.utexas.edu
2967912Shestness@cs.utexas.edu            // Check if this writeback is less restrictive that the previous
2977912Shestness@cs.utexas.edu            // and if so setup another one immediately following it
2987912Shestness@cs.utexas.edu            if (wbOut) {
2997912Shestness@cs.utexas.edu                if (aMask < wbAlignment) {
3007912Shestness@cs.utexas.edu                    moreToWb = true;
3017912Shestness@cs.utexas.edu                    wbAlignment = aMask;
3027912Shestness@cs.utexas.edu                }
3037912Shestness@cs.utexas.edu                DPRINTF(EthernetDesc, "Writing back already in process, returning\n");
3047912Shestness@cs.utexas.edu                return;
3057912Shestness@cs.utexas.edu            }
3067912Shestness@cs.utexas.edu
3077912Shestness@cs.utexas.edu            moreToWb = false;
3087912Shestness@cs.utexas.edu            wbAlignment = aMask;
3097912Shestness@cs.utexas.edu
3107912Shestness@cs.utexas.edu
3117912Shestness@cs.utexas.edu            DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
3127912Shestness@cs.utexas.edu                    "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
3137912Shestness@cs.utexas.edu                    curHead, descTail(), descLen(), cachePnt, max_to_wb,
3147912Shestness@cs.utexas.edu                    descLeft());
3157912Shestness@cs.utexas.edu
3167912Shestness@cs.utexas.edu            if (max_to_wb + curHead >= descLen()) {
3177912Shestness@cs.utexas.edu                max_to_wb = descLen() - curHead;
3187912Shestness@cs.utexas.edu                moreToWb = true;
3197912Shestness@cs.utexas.edu                // this is by definition aligned correctly
3207912Shestness@cs.utexas.edu            } else if (wbAlignment != 0) {
3217912Shestness@cs.utexas.edu                // align the wb point to the mask
3227912Shestness@cs.utexas.edu                max_to_wb = max_to_wb & ~wbAlignment;
3237912Shestness@cs.utexas.edu            }
3247912Shestness@cs.utexas.edu
3257912Shestness@cs.utexas.edu            DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
3267912Shestness@cs.utexas.edu
3277912Shestness@cs.utexas.edu            if (max_to_wb <= 0) {
3287912Shestness@cs.utexas.edu                if (usedCache.size())
3297912Shestness@cs.utexas.edu                    igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
3307912Shestness@cs.utexas.edu                else
3317912Shestness@cs.utexas.edu                    igbe->anWe(annSmWb, annUsedCacheQ);
3327912Shestness@cs.utexas.edu                return;
3337912Shestness@cs.utexas.edu            }
3347912Shestness@cs.utexas.edu
3357912Shestness@cs.utexas.edu            wbOut = max_to_wb;
3367912Shestness@cs.utexas.edu
3377912Shestness@cs.utexas.edu            assert(!wbDelayEvent.scheduled());
3387912Shestness@cs.utexas.edu            igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
3397912Shestness@cs.utexas.edu            igbe->anBegin(annSmWb, "Prepare Writeback Desc");
3407912Shestness@cs.utexas.edu        }
3417912Shestness@cs.utexas.edu
3427912Shestness@cs.utexas.edu        void writeback1()
3437912Shestness@cs.utexas.edu        {
3447912Shestness@cs.utexas.edu            // If we're draining delay issuing this DMA
3457912Shestness@cs.utexas.edu            if (igbe->getState() != SimObject::Running) {
3467912Shestness@cs.utexas.edu                igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
3477912Shestness@cs.utexas.edu                return;
3487912Shestness@cs.utexas.edu            }
3497912Shestness@cs.utexas.edu
3507912Shestness@cs.utexas.edu            DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
3517912Shestness@cs.utexas.edu
3527912Shestness@cs.utexas.edu            for (int x = 0; x < wbOut; x++) {
3537912Shestness@cs.utexas.edu                assert(usedCache.size());
3547912Shestness@cs.utexas.edu                memcpy(&wbBuf[x], usedCache[x], sizeof(T));
3557912Shestness@cs.utexas.edu                igbe->anPq(annSmWb, annUsedCacheQ);
3567912Shestness@cs.utexas.edu                igbe->anPq(annSmWb, annDescQ);
3577912Shestness@cs.utexas.edu                igbe->anQ(annSmWb, annUsedDescQ);
3587912Shestness@cs.utexas.edu            }
3597912Shestness@cs.utexas.edu
3607912Shestness@cs.utexas.edu
3617912Shestness@cs.utexas.edu            igbe->anBegin(annSmWb, "Writeback Desc DMA");
3627912Shestness@cs.utexas.edu
3637912Shestness@cs.utexas.edu            assert(wbOut);
3647912Shestness@cs.utexas.edu            igbe->dmaWrite(igbe->platform->pciToDma(descBase() + descHead() * sizeof(T)),
3657912Shestness@cs.utexas.edu                    wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
3667912Shestness@cs.utexas.edu                    igbe->wbCompDelay);
3677912Shestness@cs.utexas.edu        }
3687912Shestness@cs.utexas.edu        EventWrapper<DescCache, &DescCache::writeback1> wbDelayEvent;
3697912Shestness@cs.utexas.edu
3707912Shestness@cs.utexas.edu        /** Fetch a chunk of descriptors into the descriptor cache.
3717912Shestness@cs.utexas.edu         * Calls fetchComplete when the memory system returns the data
3727912Shestness@cs.utexas.edu         */
3737912Shestness@cs.utexas.edu
3747912Shestness@cs.utexas.edu        void fetchDescriptors()
3757912Shestness@cs.utexas.edu        {
3767912Shestness@cs.utexas.edu            size_t max_to_fetch;
3777912Shestness@cs.utexas.edu
3787912Shestness@cs.utexas.edu            if (curFetching) {
3797912Shestness@cs.utexas.edu                DPRINTF(EthernetDesc, "Currently fetching %d descriptors, returning\n", curFetching);
3807912Shestness@cs.utexas.edu                return;
3817912Shestness@cs.utexas.edu            }
3827912Shestness@cs.utexas.edu
3837912Shestness@cs.utexas.edu            if (descTail() >= cachePnt)
3847912Shestness@cs.utexas.edu                max_to_fetch = descTail() - cachePnt;
3857912Shestness@cs.utexas.edu            else
3867912Shestness@cs.utexas.edu                max_to_fetch = descLen() - cachePnt;
3877912Shestness@cs.utexas.edu
3887912Shestness@cs.utexas.edu            size_t free_cache = size - usedCache.size() - unusedCache.size();
3897912Shestness@cs.utexas.edu
3907912Shestness@cs.utexas.edu            if (!max_to_fetch)
3917912Shestness@cs.utexas.edu                igbe->anWe(annSmFetch, annUnusedDescQ);
3927912Shestness@cs.utexas.edu            else
3937912Shestness@cs.utexas.edu                igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
3947912Shestness@cs.utexas.edu
3957912Shestness@cs.utexas.edu            if (max_to_fetch) {
3967912Shestness@cs.utexas.edu                if (!free_cache)
3977912Shestness@cs.utexas.edu                    igbe->anWf(annSmFetch, annDescQ);
3987912Shestness@cs.utexas.edu                else
3997912Shestness@cs.utexas.edu                    igbe->anRq(annSmFetch, annDescQ, free_cache);
4007912Shestness@cs.utexas.edu            }
4017912Shestness@cs.utexas.edu
4027912Shestness@cs.utexas.edu            max_to_fetch = std::min(max_to_fetch, free_cache);
4037912Shestness@cs.utexas.edu
4047912Shestness@cs.utexas.edu
4057912Shestness@cs.utexas.edu            DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
4067912Shestness@cs.utexas.edu                    "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
4077912Shestness@cs.utexas.edu                    descHead(), descTail(), descLen(), cachePnt,
4087912Shestness@cs.utexas.edu                    max_to_fetch, descLeft());
4097912Shestness@cs.utexas.edu
4107912Shestness@cs.utexas.edu            // Nothing to do
4117912Shestness@cs.utexas.edu            if (max_to_fetch == 0)
4127912Shestness@cs.utexas.edu                return;
4137912Shestness@cs.utexas.edu
4147912Shestness@cs.utexas.edu            // So we don't have two descriptor fetches going on at once
4157912Shestness@cs.utexas.edu            curFetching = max_to_fetch;
4167912Shestness@cs.utexas.edu
4177912Shestness@cs.utexas.edu            assert(!fetchDelayEvent.scheduled());
4187912Shestness@cs.utexas.edu            igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
4197912Shestness@cs.utexas.edu            igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
4207912Shestness@cs.utexas.edu        }
4217912Shestness@cs.utexas.edu
4227912Shestness@cs.utexas.edu        void fetchDescriptors1()
4237912Shestness@cs.utexas.edu        {
4247912Shestness@cs.utexas.edu            // If we're draining delay issuing this DMA
4257912Shestness@cs.utexas.edu            if (igbe->getState() != SimObject::Running) {
4267912Shestness@cs.utexas.edu                igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
4277912Shestness@cs.utexas.edu                return;
4287912Shestness@cs.utexas.edu            }
4297912Shestness@cs.utexas.edu
4307912Shestness@cs.utexas.edu            igbe->anBegin(annSmFetch, "Fetch Desc");
4317912Shestness@cs.utexas.edu
4327912Shestness@cs.utexas.edu            DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
4337912Shestness@cs.utexas.edu                    descBase() + cachePnt * sizeof(T),
4347912Shestness@cs.utexas.edu                    igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
4357912Shestness@cs.utexas.edu                    curFetching * sizeof(T));
4367912Shestness@cs.utexas.edu            assert(curFetching);
4377912Shestness@cs.utexas.edu            igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
4387912Shestness@cs.utexas.edu                    curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
4397912Shestness@cs.utexas.edu                    igbe->fetchCompDelay);
4407912Shestness@cs.utexas.edu        }
4417912Shestness@cs.utexas.edu
4427912Shestness@cs.utexas.edu        EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
4437912Shestness@cs.utexas.edu
4447912Shestness@cs.utexas.edu        /** Called by event when dma to read descriptors is completed
4457912Shestness@cs.utexas.edu         */
4467912Shestness@cs.utexas.edu        void fetchComplete()
4477912Shestness@cs.utexas.edu        {
4487912Shestness@cs.utexas.edu            T *newDesc;
4497912Shestness@cs.utexas.edu            igbe->anBegin(annSmFetch, "Fetch Complete");
4507912Shestness@cs.utexas.edu            for (int x = 0; x < curFetching; x++) {
4517912Shestness@cs.utexas.edu                newDesc = new T;
4527912Shestness@cs.utexas.edu                memcpy(newDesc, &fetchBuf[x], sizeof(T));
4537912Shestness@cs.utexas.edu                unusedCache.push_back(newDesc);
4547912Shestness@cs.utexas.edu                igbe->anDq(annSmFetch, annUnusedDescQ);
4557912Shestness@cs.utexas.edu                igbe->anQ(annSmFetch, annUnusedCacheQ);
4567912Shestness@cs.utexas.edu                igbe->anQ(annSmFetch, annDescQ);
4577912Shestness@cs.utexas.edu            }
4587912Shestness@cs.utexas.edu
4597912Shestness@cs.utexas.edu
4607912Shestness@cs.utexas.edu#ifndef NDEBUG
4617912Shestness@cs.utexas.edu            int oldCp = cachePnt;
4627912Shestness@cs.utexas.edu#endif
4637912Shestness@cs.utexas.edu
4647912Shestness@cs.utexas.edu            cachePnt += curFetching;
4657912Shestness@cs.utexas.edu            assert(cachePnt <= descLen());
4667912Shestness@cs.utexas.edu            if (cachePnt == descLen())
4677912Shestness@cs.utexas.edu                cachePnt = 0;
4687912Shestness@cs.utexas.edu
4697912Shestness@cs.utexas.edu            curFetching = 0;
4707912Shestness@cs.utexas.edu
4717912Shestness@cs.utexas.edu            DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
4727912Shestness@cs.utexas.edu                    oldCp, cachePnt);
4737912Shestness@cs.utexas.edu
4747912Shestness@cs.utexas.edu            if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
4757912Shestness@cs.utexas.edu                    cachePnt)) == 0)
4767912Shestness@cs.utexas.edu            {
4777912Shestness@cs.utexas.edu                igbe->anWe(annSmFetch, annUnusedDescQ);
4787912Shestness@cs.utexas.edu            } else if (!(size - usedCache.size() - unusedCache.size())) {
4797912Shestness@cs.utexas.edu                igbe->anWf(annSmFetch, annDescQ);
4807912Shestness@cs.utexas.edu            } else {
4817912Shestness@cs.utexas.edu                igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
4827912Shestness@cs.utexas.edu            }
4837912Shestness@cs.utexas.edu
4847912Shestness@cs.utexas.edu            enableSm();
4857912Shestness@cs.utexas.edu            igbe->checkDrain();
4867912Shestness@cs.utexas.edu        }
4877912Shestness@cs.utexas.edu
4887912Shestness@cs.utexas.edu        EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
4897912Shestness@cs.utexas.edu
4907912Shestness@cs.utexas.edu        /** Called by event when dma to writeback descriptors is completed
4917912Shestness@cs.utexas.edu         */
4927912Shestness@cs.utexas.edu        void wbComplete()
4937912Shestness@cs.utexas.edu        {
4947912Shestness@cs.utexas.edu
4957912Shestness@cs.utexas.edu            igbe->anBegin(annSmWb, "Finish Writeback");
4967912Shestness@cs.utexas.edu
4977912Shestness@cs.utexas.edu            long  curHead = descHead();
4987912Shestness@cs.utexas.edu#ifndef NDEBUG
4997912Shestness@cs.utexas.edu            long oldHead = curHead;
5007912Shestness@cs.utexas.edu#endif
5017912Shestness@cs.utexas.edu
5027912Shestness@cs.utexas.edu            for (int x = 0; x < wbOut; x++) {
5037912Shestness@cs.utexas.edu                assert(usedCache.size());
5047912Shestness@cs.utexas.edu                delete usedCache[0];
5057912Shestness@cs.utexas.edu                usedCache.pop_front();
5067912Shestness@cs.utexas.edu
5077912Shestness@cs.utexas.edu                igbe->anDq(annSmWb, annUsedCacheQ);
5087912Shestness@cs.utexas.edu                igbe->anDq(annSmWb, annDescQ);
5097912Shestness@cs.utexas.edu            }
5107912Shestness@cs.utexas.edu
5117912Shestness@cs.utexas.edu            curHead += wbOut;
5128096Sgblack@eecs.umich.edu            wbOut = 0;
5137912Shestness@cs.utexas.edu
5147912Shestness@cs.utexas.edu            if (curHead >= descLen())
5157912Shestness@cs.utexas.edu                curHead -= descLen();
5167912Shestness@cs.utexas.edu
5177912Shestness@cs.utexas.edu            // Update the head
5187912Shestness@cs.utexas.edu            updateHead(curHead);
5197912Shestness@cs.utexas.edu
5207912Shestness@cs.utexas.edu            DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
5217912Shestness@cs.utexas.edu                    oldHead, curHead);
5227912Shestness@cs.utexas.edu
5237912Shestness@cs.utexas.edu            // If we still have more to wb, call wb now
5247912Shestness@cs.utexas.edu            actionAfterWb();
5257912Shestness@cs.utexas.edu            if (moreToWb) {
5267912Shestness@cs.utexas.edu                moreToWb = false;
5277912Shestness@cs.utexas.edu                DPRINTF(EthernetDesc, "Writeback has more todo\n");
5287912Shestness@cs.utexas.edu                writeback(wbAlignment);
5297912Shestness@cs.utexas.edu            }
5307912Shestness@cs.utexas.edu
5317912Shestness@cs.utexas.edu            if (!wbOut) {
5327912Shestness@cs.utexas.edu                igbe->checkDrain();
5337912Shestness@cs.utexas.edu                if (usedCache.size())
5347912Shestness@cs.utexas.edu                    igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
5357912Shestness@cs.utexas.edu                else
5367912Shestness@cs.utexas.edu                    igbe->anWe(annSmWb, annUsedCacheQ);
5377912Shestness@cs.utexas.edu            }
5387912Shestness@cs.utexas.edu            fetchAfterWb();
5397912Shestness@cs.utexas.edu        }
5407912Shestness@cs.utexas.edu
5417912Shestness@cs.utexas.edu
5427912Shestness@cs.utexas.edu        EventWrapper<DescCache, &DescCache::wbComplete> wbEvent;
5437912Shestness@cs.utexas.edu
5447912Shestness@cs.utexas.edu        /* Return the number of descriptors left in the ring, so the device has
5457912Shestness@cs.utexas.edu         * a way to figure out if it needs to interrupt.
5467912Shestness@cs.utexas.edu         */
5477912Shestness@cs.utexas.edu        int descLeft() const
5487912Shestness@cs.utexas.edu        {
5497912Shestness@cs.utexas.edu            int left = unusedCache.size();
5507912Shestness@cs.utexas.edu            if (cachePnt >= descTail())
5517912Shestness@cs.utexas.edu                left += (descLen() - cachePnt + descTail());
5527912Shestness@cs.utexas.edu            else
5537912Shestness@cs.utexas.edu                left += (descTail() - cachePnt);
5547912Shestness@cs.utexas.edu
5557912Shestness@cs.utexas.edu            return left;
5567912Shestness@cs.utexas.edu        }
5577912Shestness@cs.utexas.edu
5587912Shestness@cs.utexas.edu        /* Return the number of descriptors used and not written back.
5597912Shestness@cs.utexas.edu         */
5607912Shestness@cs.utexas.edu        int descUsed() const { return usedCache.size(); }
5617912Shestness@cs.utexas.edu
5627912Shestness@cs.utexas.edu        /* Return the number of cache unused descriptors we have. */
5637912Shestness@cs.utexas.edu        int descUnused() const {return unusedCache.size(); }
5647912Shestness@cs.utexas.edu
5657912Shestness@cs.utexas.edu        /* Get into a state where the descriptor address/head/etc colud be
5667912Shestness@cs.utexas.edu         * changed */
5677912Shestness@cs.utexas.edu        void reset()
5687912Shestness@cs.utexas.edu        {
5697912Shestness@cs.utexas.edu            DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
5707912Shestness@cs.utexas.edu            for (int x = 0; x < usedCache.size(); x++)
5717912Shestness@cs.utexas.edu                delete usedCache[x];
5727912Shestness@cs.utexas.edu            for (int x = 0; x < unusedCache.size(); x++)
5737912Shestness@cs.utexas.edu                delete unusedCache[x];
5747912Shestness@cs.utexas.edu
5757912Shestness@cs.utexas.edu            usedCache.clear();
5767912Shestness@cs.utexas.edu            unusedCache.clear();
5777912Shestness@cs.utexas.edu
5787912Shestness@cs.utexas.edu            cachePnt = 0;
5797912Shestness@cs.utexas.edu
5807912Shestness@cs.utexas.edu        }
5817912Shestness@cs.utexas.edu
5828096Sgblack@eecs.umich.edu        virtual void serialize(std::ostream &os)
5837912Shestness@cs.utexas.edu        {
5847912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(cachePnt);
5857912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(curFetching);
5867912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(wbOut);
5877912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(moreToWb);
5887912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(wbAlignment);
5897912Shestness@cs.utexas.edu
5907912Shestness@cs.utexas.edu            int usedCacheSize = usedCache.size();
5917912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(usedCacheSize);
5927912Shestness@cs.utexas.edu            for(int x = 0; x < usedCacheSize; x++) {
5937912Shestness@cs.utexas.edu                arrayParamOut(os, csprintf("usedCache_%d", x),
5947912Shestness@cs.utexas.edu                        (uint8_t*)usedCache[x],sizeof(T));
5957912Shestness@cs.utexas.edu            }
5967912Shestness@cs.utexas.edu
5977912Shestness@cs.utexas.edu            int unusedCacheSize = unusedCache.size();
5987912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(unusedCacheSize);
5997912Shestness@cs.utexas.edu            for(int x = 0; x < unusedCacheSize; x++) {
6007912Shestness@cs.utexas.edu                arrayParamOut(os, csprintf("unusedCache_%d", x),
6017912Shestness@cs.utexas.edu                        (uint8_t*)unusedCache[x],sizeof(T));
6027912Shestness@cs.utexas.edu            }
6037912Shestness@cs.utexas.edu
6047912Shestness@cs.utexas.edu            Tick fetch_delay = 0, wb_delay = 0;
6057912Shestness@cs.utexas.edu            if (fetchDelayEvent.scheduled())
6067912Shestness@cs.utexas.edu                fetch_delay = fetchDelayEvent.when();
6077912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(fetch_delay);
6087912Shestness@cs.utexas.edu            if (wbDelayEvent.scheduled())
6097912Shestness@cs.utexas.edu                wb_delay = wbDelayEvent.when();
6107912Shestness@cs.utexas.edu            SERIALIZE_SCALAR(wb_delay);
6117912Shestness@cs.utexas.edu
6127912Shestness@cs.utexas.edu
6137912Shestness@cs.utexas.edu        }
6147912Shestness@cs.utexas.edu
6157912Shestness@cs.utexas.edu        virtual void unserialize(Checkpoint *cp, const std::string &section)
6167912Shestness@cs.utexas.edu        {
6177912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(cachePnt);
6187912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(curFetching);
6197912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(wbOut);
6207912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(moreToWb);
6217912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(wbAlignment);
6227912Shestness@cs.utexas.edu
6237912Shestness@cs.utexas.edu            int usedCacheSize;
6247912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(usedCacheSize);
6257912Shestness@cs.utexas.edu            T *temp;
6267912Shestness@cs.utexas.edu            for(int x = 0; x < usedCacheSize; x++) {
6277912Shestness@cs.utexas.edu                temp = new T;
6287912Shestness@cs.utexas.edu                arrayParamIn(cp, section, csprintf("usedCache_%d", x),
6297912Shestness@cs.utexas.edu                        (uint8_t*)temp,sizeof(T));
6307912Shestness@cs.utexas.edu                usedCache.push_back(temp);
6317912Shestness@cs.utexas.edu            }
6327912Shestness@cs.utexas.edu
6337912Shestness@cs.utexas.edu            int unusedCacheSize;
6347912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(unusedCacheSize);
6357912Shestness@cs.utexas.edu            for(int x = 0; x < unusedCacheSize; x++) {
6367912Shestness@cs.utexas.edu                temp = new T;
6377912Shestness@cs.utexas.edu                arrayParamIn(cp, section, csprintf("unusedCache_%d", x),
6387912Shestness@cs.utexas.edu                        (uint8_t*)temp,sizeof(T));
6397912Shestness@cs.utexas.edu                unusedCache.push_back(temp);
6407912Shestness@cs.utexas.edu            }
6417912Shestness@cs.utexas.edu            Tick fetch_delay = 0, wb_delay = 0;
6427912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(fetch_delay);
6437912Shestness@cs.utexas.edu            UNSERIALIZE_SCALAR(wb_delay);
6447912Shestness@cs.utexas.edu            if (fetch_delay)
6457912Shestness@cs.utexas.edu                igbe->schedule(fetchDelayEvent, fetch_delay);
6467912Shestness@cs.utexas.edu            if (wb_delay)
6477912Shestness@cs.utexas.edu                igbe->schedule(wbDelayEvent, wb_delay);
6487912Shestness@cs.utexas.edu
6497912Shestness@cs.utexas.edu
6507912Shestness@cs.utexas.edu        }
6515245Sgblack@eecs.umich.edu        virtual bool hasOutstandingEvents() {
6525245Sgblack@eecs.umich.edu            return wbEvent.scheduled() || fetchEvent.scheduled();
6535245Sgblack@eecs.umich.edu        }
6545245Sgblack@eecs.umich.edu
6555245Sgblack@eecs.umich.edu     };
6565245Sgblack@eecs.umich.edu
6575245Sgblack@eecs.umich.edu
6585897Sgblack@eecs.umich.edu    class RxDescCache : public DescCache<iGbReg::RxDesc>
6595897Sgblack@eecs.umich.edu    {
6605897Sgblack@eecs.umich.edu      protected:
6617912Shestness@cs.utexas.edu        virtual Addr descBase() const { return igbe->regs.rdba(); }
6625245Sgblack@eecs.umich.edu        virtual long descHead() const { return igbe->regs.rdh(); }
6635897Sgblack@eecs.umich.edu        virtual long descLen() const { return igbe->regs.rdlen() >> 4; }
6645897Sgblack@eecs.umich.edu        virtual long descTail() const { return igbe->regs.rdt(); }
6655245Sgblack@eecs.umich.edu        virtual void updateHead(long h) { igbe->regs.rdh(h); }
6665245Sgblack@eecs.umich.edu        virtual void enableSm();
6675245Sgblack@eecs.umich.edu        virtual void fetchAfterWb() {
6685245Sgblack@eecs.umich.edu            if (!igbe->rxTick && igbe->getState() == SimObject::Running)
6695245Sgblack@eecs.umich.edu                fetchDescriptors();
6705245Sgblack@eecs.umich.edu        }
6715897Sgblack@eecs.umich.edu
6725897Sgblack@eecs.umich.edu        bool pktDone;
6737912Shestness@cs.utexas.edu
6745245Sgblack@eecs.umich.edu        /** Variable to head with header/data completion events */
6755897Sgblack@eecs.umich.edu        int splitCount;
6765897Sgblack@eecs.umich.edu
6775245Sgblack@eecs.umich.edu        /** Bytes of packet that have been copied, so we know when to set EOP */
6785245Sgblack@eecs.umich.edu        int bytesCopied;
6795245Sgblack@eecs.umich.edu
6805245Sgblack@eecs.umich.edu      public:
6815245Sgblack@eecs.umich.edu        RxDescCache(IGbE *i, std::string n, int s);
6827912Shestness@cs.utexas.edu
6837912Shestness@cs.utexas.edu        /** Write the given packet into the buffer(s) pointed to by the
6845245Sgblack@eecs.umich.edu         * descriptor and update the book keeping. Should only be called when
6857912Shestness@cs.utexas.edu         * there are no dma's pending.
6867912Shestness@cs.utexas.edu         * @param packet ethernet packet to write
6877912Shestness@cs.utexas.edu         * @param pkt_offset bytes already copied from the packet to memory
6887912Shestness@cs.utexas.edu         * @return pkt_offset + number of bytes copied during this call
6897912Shestness@cs.utexas.edu         */
6907912Shestness@cs.utexas.edu        int writePacket(EthPacketPtr packet, int pkt_offset);
6917912Shestness@cs.utexas.edu
6927912Shestness@cs.utexas.edu        /** Called by event when dma to write packet is completed
6937912Shestness@cs.utexas.edu         */
6947912Shestness@cs.utexas.edu        void pktComplete();
6957912Shestness@cs.utexas.edu
6967912Shestness@cs.utexas.edu        /** Check if the dma on the packet has completed and RX state machine
6977912Shestness@cs.utexas.edu         * can continue
6987912Shestness@cs.utexas.edu         */
6997912Shestness@cs.utexas.edu        bool packetDone();
7007912Shestness@cs.utexas.edu
7017912Shestness@cs.utexas.edu        EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
7027912Shestness@cs.utexas.edu
7037912Shestness@cs.utexas.edu        // Event to handle issuing header and data write at the same time
7047912Shestness@cs.utexas.edu        // and only callking pktComplete() when both are completed
7055245Sgblack@eecs.umich.edu        void pktSplitDone();
7065245Sgblack@eecs.umich.edu        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent;
7075895Sgblack@eecs.umich.edu        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent;
7087912Shestness@cs.utexas.edu
7095895Sgblack@eecs.umich.edu        virtual bool hasOutstandingEvents();
7105904Sgblack@eecs.umich.edu
7115895Sgblack@eecs.umich.edu        virtual void serialize(std::ostream &os);
7126023Snate@binkert.org        virtual void unserialize(Checkpoint *cp, const std::string &section);
7136023Snate@binkert.org    };
7146023Snate@binkert.org    friend class RxDescCache;
7155895Sgblack@eecs.umich.edu
7165895Sgblack@eecs.umich.edu    RxDescCache rxDescCache;
7177912Shestness@cs.utexas.edu
7185245Sgblack@eecs.umich.edu    class TxDescCache  : public DescCache<iGbReg::TxDesc>
7195245Sgblack@eecs.umich.edu    {
7205245Sgblack@eecs.umich.edu      protected:
7215245Sgblack@eecs.umich.edu        virtual Addr descBase() const { return igbe->regs.tdba(); }
7225245Sgblack@eecs.umich.edu        virtual long descHead() const { return igbe->regs.tdh(); }
7235245Sgblack@eecs.umich.edu        virtual long descTail() const { return igbe->regs.tdt(); }
724        virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
725        virtual void updateHead(long h) { igbe->regs.tdh(h); }
726        virtual void enableSm();
727        virtual void actionAfterWb();
728        virtual void fetchAfterWb() {
729            if (!igbe->txTick && igbe->getState() == SimObject::Running)
730                fetchDescriptors();
731        }
732
733
734
735        bool pktDone;
736        bool isTcp;
737        bool pktWaiting;
738        bool pktMultiDesc;
739        Addr completionAddress;
740        bool completionEnabled;
741        uint32_t descEnd;
742
743
744        // tso variables
745        bool useTso;
746        Addr tsoHeaderLen;
747        Addr tsoMss;
748        Addr tsoTotalLen;
749        Addr tsoUsedLen;
750        Addr tsoPrevSeq;;
751        Addr tsoPktPayloadBytes;
752        bool tsoLoadedHeader;
753        bool tsoPktHasHeader;
754        uint8_t tsoHeader[256];
755        Addr tsoDescBytesUsed;
756        Addr tsoCopyBytes;
757        int tsoPkts;
758
759      public:
760        TxDescCache(IGbE *i, std::string n, int s);
761
762        /** Tell the cache to DMA a packet from main memory into its buffer and
763         * return the size the of the packet to reserve space in tx fifo.
764         * @return size of the packet
765         */
766        int getPacketSize(EthPacketPtr p);
767        void getPacketData(EthPacketPtr p);
768        void processContextDesc();
769
770        /** Return the number of dsecriptors in a cache block for threshold
771         * operations.
772         */
773        int descInBlock(int num_desc) { return num_desc /
774            igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc); }
775        /** Ask if the packet has been transfered so the state machine can give
776         * it to the fifo.
777         * @return packet available in descriptor cache
778         */
779        bool packetAvailable();
780
781        /** Ask if we are still waiting for the packet to be transfered.
782         * @return packet still in transit.
783         */
784        bool packetWaiting() { return pktWaiting; }
785
786        /** Ask if this packet is composed of multiple descriptors
787         * so even if we've got data, we need to wait for more before
788         * we can send it out.
789         * @return packet can't be sent out because it's a multi-descriptor
790         * packet
791         */
792        bool packetMultiDesc() { return pktMultiDesc;}
793
794        /** Called by event when dma to write packet is completed
795         */
796        void pktComplete();
797        EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
798
799        void headerComplete();
800        EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
801
802
803        void completionWriteback(Addr a, bool enabled) {
804            DPRINTF(EthernetDesc, "Completion writeback Addr: %#x enabled: %d\n",
805                    a, enabled);
806            completionAddress = a;
807            completionEnabled = enabled;
808        }
809
810        virtual bool hasOutstandingEvents();
811
812        void nullCallback() { DPRINTF(EthernetDesc, "Completion writeback complete\n"); }
813        EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
814
815        virtual void serialize(std::ostream &os);
816        virtual void unserialize(Checkpoint *cp, const std::string &section);
817
818    };
819    friend class TxDescCache;
820
821    TxDescCache txDescCache;
822
823  public:
824    typedef IGbEParams Params;
825    const Params *
826    params() const
827    {
828        return dynamic_cast<const Params *>(_params);
829    }
830    IGbE(const Params *params);
831    ~IGbE() {}
832    virtual void init();
833
834    virtual EtherInt *getEthPort(const std::string &if_name, int idx);
835
836    Tick clock;
837    Tick lastInterrupt;
838    inline Tick ticks(int numCycles) const { return numCycles * clock; }
839
840    virtual Tick read(PacketPtr pkt);
841    virtual Tick write(PacketPtr pkt);
842
843    virtual Tick writeConfig(PacketPtr pkt);
844
845    bool ethRxPkt(EthPacketPtr packet);
846    void ethTxDone();
847
848    virtual void serialize(std::ostream &os);
849    virtual void unserialize(Checkpoint *cp, const std::string &section);
850    virtual unsigned int drain(Event *de);
851    virtual void resume();
852
853};
854
855class IGbEInt : public EtherInt
856{
857  private:
858    IGbE *dev;
859
860  public:
861    IGbEInt(const std::string &name, IGbE *d)
862        : EtherInt(name), dev(d)
863    { }
864
865    virtual bool recvPacket(EthPacketPtr pkt) { return dev->ethRxPkt(pkt); }
866    virtual void sendDone() { dev->ethTxDone(); }
867};
868
869
870
871
872
873#endif //__DEV_I8254XGBE_HH__
874
875