i8254xGBe.hh revision 8902
16717Sgblack@eecs.umich.edu/*
210337SAndrew.Bardsley@arm.com * Copyright (c) 2006 The Regents of The University of Michigan
37310Sgblack@eecs.umich.edu * All rights reserved.
47310Sgblack@eecs.umich.edu *
57310Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67310Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77310Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87310Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97310Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107310Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117310Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127310Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137310Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
146717Sgblack@eecs.umich.edu * this software without specific prior written permission.
156717Sgblack@eecs.umich.edu *
166717Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176717Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186717Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196717Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206717Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216717Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226717Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236717Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246717Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256717Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266717Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276717Sgblack@eecs.umich.edu *
286717Sgblack@eecs.umich.edu * Authors: Ali Saidi
296717Sgblack@eecs.umich.edu */
306717Sgblack@eecs.umich.edu
316717Sgblack@eecs.umich.edu/* @file
326717Sgblack@eecs.umich.edu * Device model for Intel's 8254x line of gigabit ethernet controllers.
336717Sgblack@eecs.umich.edu */
346717Sgblack@eecs.umich.edu
356717Sgblack@eecs.umich.edu#ifndef __DEV_I8254XGBE_HH__
366717Sgblack@eecs.umich.edu#define __DEV_I8254XGBE_HH__
376717Sgblack@eecs.umich.edu
386717Sgblack@eecs.umich.edu#include <deque>
396717Sgblack@eecs.umich.edu#include <string>
406717Sgblack@eecs.umich.edu
416717Sgblack@eecs.umich.edu#include "base/cp_annotate.hh"
426717Sgblack@eecs.umich.edu#include "base/inet.hh"
438229Snate@binkert.org#include "debug/EthernetDesc.hh"
446717Sgblack@eecs.umich.edu#include "debug/EthernetIntr.hh"
456717Sgblack@eecs.umich.edu#include "dev/etherdevice.hh"
466717Sgblack@eecs.umich.edu#include "dev/etherint.hh"
476717Sgblack@eecs.umich.edu#include "dev/etherpkt.hh"
487310Sgblack@eecs.umich.edu#include "dev/i8254xGBe_defs.hh"
497310Sgblack@eecs.umich.edu#include "dev/pcidev.hh"
506717Sgblack@eecs.umich.edu#include "dev/pktfifo.hh"
516717Sgblack@eecs.umich.edu#include "params/IGbE.hh"
526717Sgblack@eecs.umich.edu#include "sim/eventq.hh"
536717Sgblack@eecs.umich.edu
546717Sgblack@eecs.umich.educlass IGbEInt;
556717Sgblack@eecs.umich.edu
566717Sgblack@eecs.umich.educlass IGbE : public EtherDevice
576717Sgblack@eecs.umich.edu{
586717Sgblack@eecs.umich.edu  private:
596717Sgblack@eecs.umich.edu    IGbEInt *etherInt;
606717Sgblack@eecs.umich.edu    CPA *cpa;
616717Sgblack@eecs.umich.edu
626717Sgblack@eecs.umich.edu    // device registers
636717Sgblack@eecs.umich.edu    iGbReg::Regs regs;
646717Sgblack@eecs.umich.edu
656717Sgblack@eecs.umich.edu    // eeprom data, status and control bits
666717Sgblack@eecs.umich.edu    int eeOpBits, eeAddrBits, eeDataBits;
676717Sgblack@eecs.umich.edu    uint8_t eeOpcode, eeAddr;
686717Sgblack@eecs.umich.edu    uint16_t flash[iGbReg::EEPROM_SIZE];
696717Sgblack@eecs.umich.edu
706717Sgblack@eecs.umich.edu    // The drain event if we have one
716717Sgblack@eecs.umich.edu    Event *drainEvent;
726717Sgblack@eecs.umich.edu
736717Sgblack@eecs.umich.edu    // cached parameters from params struct
746717Sgblack@eecs.umich.edu    bool useFlowControl;
756717Sgblack@eecs.umich.edu
766717Sgblack@eecs.umich.edu    // packet fifos
776717Sgblack@eecs.umich.edu    PacketFifo rxFifo;
786717Sgblack@eecs.umich.edu    PacketFifo txFifo;
796717Sgblack@eecs.umich.edu
806717Sgblack@eecs.umich.edu    // Packet that we are currently putting into the txFifo
816717Sgblack@eecs.umich.edu    EthPacketPtr txPacket;
826717Sgblack@eecs.umich.edu
836717Sgblack@eecs.umich.edu    // Should to Rx/Tx State machine tick?
846717Sgblack@eecs.umich.edu    bool rxTick;
856717Sgblack@eecs.umich.edu    bool txTick;
8610037SARM gem5 Developers    bool txFifoTick;
8710037SARM gem5 Developers
8810037SARM gem5 Developers    bool rxDmaPacket;
896717Sgblack@eecs.umich.edu
906717Sgblack@eecs.umich.edu    // Number of bytes copied from current RX packet
916717Sgblack@eecs.umich.edu    unsigned pktOffset;
926717Sgblack@eecs.umich.edu
936717Sgblack@eecs.umich.edu    // Delays in managaging descriptors
946717Sgblack@eecs.umich.edu    Tick fetchDelay, wbDelay;
956717Sgblack@eecs.umich.edu    Tick fetchCompDelay, wbCompDelay;
966717Sgblack@eecs.umich.edu    Tick rxWriteDelay, txReadDelay;
976717Sgblack@eecs.umich.edu
986717Sgblack@eecs.umich.edu    // Event and function to deal with RDTR timer expiring
996717Sgblack@eecs.umich.edu    void rdtrProcess() {
1006717Sgblack@eecs.umich.edu        rxDescCache.writeback(0);
1016717Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
1026717Sgblack@eecs.umich.edu                "Posting RXT interrupt because RDTR timer expired\n");
1036717Sgblack@eecs.umich.edu        postInterrupt(iGbReg::IT_RXT);
1046717Sgblack@eecs.umich.edu    }
1056717Sgblack@eecs.umich.edu
1066717Sgblack@eecs.umich.edu    //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
1076717Sgblack@eecs.umich.edu    EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
1086717Sgblack@eecs.umich.edu
1096717Sgblack@eecs.umich.edu    // Event and function to deal with RADV timer expiring
1106717Sgblack@eecs.umich.edu    void radvProcess() {
1116717Sgblack@eecs.umich.edu        rxDescCache.writeback(0);
1126717Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
1136717Sgblack@eecs.umich.edu                "Posting RXT interrupt because RADV timer expired\n");
11410037SARM gem5 Developers        postInterrupt(iGbReg::IT_RXT);
1156717Sgblack@eecs.umich.edu    }
1168140SMatt.Horsnell@arm.com
1178140SMatt.Horsnell@arm.com    //friend class EventWrapper<IGbE, &IGbE::radvProcess>;
11810037SARM gem5 Developers    EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
11910037SARM gem5 Developers
12010037SARM gem5 Developers    // Event and function to deal with TADV timer expiring
12110037SARM gem5 Developers    void tadvProcess() {
12210037SARM gem5 Developers        txDescCache.writeback(0);
12310037SARM gem5 Developers        DPRINTF(EthernetIntr,
1246717Sgblack@eecs.umich.edu                "Posting TXDW interrupt because TADV timer expired\n");
1256717Sgblack@eecs.umich.edu        postInterrupt(iGbReg::IT_TXDW);
12610037SARM gem5 Developers    }
12710037SARM gem5 Developers
12810037SARM gem5 Developers    //friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
12910037SARM gem5 Developers    EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent;
13010037SARM gem5 Developers
13110037SARM gem5 Developers    // Event and function to deal with TIDV timer expiring
13210037SARM gem5 Developers    void tidvProcess() {
13310037SARM gem5 Developers        txDescCache.writeback(0);
13410037SARM gem5 Developers        DPRINTF(EthernetIntr,
13510037SARM gem5 Developers                "Posting TXDW interrupt because TIDV timer expired\n");
13610037SARM gem5 Developers        postInterrupt(iGbReg::IT_TXDW);
13710037SARM gem5 Developers    }
13810037SARM gem5 Developers    //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
13910037SARM gem5 Developers    EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
14010037SARM gem5 Developers
14110037SARM gem5 Developers    // Main event to tick the device
14210037SARM gem5 Developers    void tick();
14310037SARM gem5 Developers    //friend class EventWrapper<IGbE, &IGbE::tick>;
14410037SARM gem5 Developers    EventWrapper<IGbE, &IGbE::tick> tickEvent;
14510037SARM gem5 Developers
14610037SARM gem5 Developers
14710037SARM gem5 Developers    uint64_t macAddr;
14810037SARM gem5 Developers
14910037SARM gem5 Developers    void rxStateMachine();
15010037SARM gem5 Developers    void txStateMachine();
15110037SARM gem5 Developers    void txWire();
15210037SARM gem5 Developers
15310037SARM gem5 Developers    /** Write an interrupt into the interrupt pending register and check mask
15410037SARM gem5 Developers     * and interrupt limit timer before sending interrupt to CPU
15510037SARM gem5 Developers     * @param t the type of interrupt we are posting
15610037SARM gem5 Developers     * @param now should we ignore the interrupt limiting timer
15710037SARM gem5 Developers     */
15810037SARM gem5 Developers    void postInterrupt(iGbReg::IntTypes t, bool now = false);
15910037SARM gem5 Developers
16010037SARM gem5 Developers    /** Check and see if changes to the mask register have caused an interrupt
16110037SARM gem5 Developers     * to need to be sent or perhaps removed an interrupt cause.
16210037SARM gem5 Developers     */
1636717Sgblack@eecs.umich.edu    void chkInterrupt();
1646717Sgblack@eecs.umich.edu
16510037SARM gem5 Developers    /** Send an interrupt to the cpu
1666717Sgblack@eecs.umich.edu     */
1676717Sgblack@eecs.umich.edu    void delayIntEvent();
1686717Sgblack@eecs.umich.edu    void cpuPostInt();
1696717Sgblack@eecs.umich.edu    // Event to moderate interrupts
1706717Sgblack@eecs.umich.edu    EventWrapper<IGbE, &IGbE::delayIntEvent> interEvent;
1716717Sgblack@eecs.umich.edu
1726717Sgblack@eecs.umich.edu    /** Clear the interupt line to the cpu
1736717Sgblack@eecs.umich.edu     */
1746717Sgblack@eecs.umich.edu    void cpuClearInt();
1756717Sgblack@eecs.umich.edu
1766717Sgblack@eecs.umich.edu    Tick intClock() { return SimClock::Int::ns * 1024; }
1776717Sgblack@eecs.umich.edu
1786717Sgblack@eecs.umich.edu    /** This function is used to restart the clock so it can handle things like
1796717Sgblack@eecs.umich.edu     * draining and resume in one place. */
1806717Sgblack@eecs.umich.edu    void restartClock();
1816717Sgblack@eecs.umich.edu
1826717Sgblack@eecs.umich.edu    /** Check if all the draining things that need to occur have occured and
1836717Sgblack@eecs.umich.edu     * handle the drain event if so.
1846717Sgblack@eecs.umich.edu     */
1856717Sgblack@eecs.umich.edu    void checkDrain();
1866717Sgblack@eecs.umich.edu
1876717Sgblack@eecs.umich.edu    void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) {
1886717Sgblack@eecs.umich.edu        cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st);
1896717Sgblack@eecs.umich.edu    }
1906717Sgblack@eecs.umich.edu
1916717Sgblack@eecs.umich.edu    void anQ(std::string sm, std::string q) {
1926717Sgblack@eecs.umich.edu        cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
1936717Sgblack@eecs.umich.edu    }
1946717Sgblack@eecs.umich.edu
1956717Sgblack@eecs.umich.edu    void anDq(std::string sm, std::string q) {
1966717Sgblack@eecs.umich.edu        cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
1976717Sgblack@eecs.umich.edu    }
1986717Sgblack@eecs.umich.edu
1996717Sgblack@eecs.umich.edu    void anPq(std::string sm, std::string q, int num = 1) {
2006717Sgblack@eecs.umich.edu        cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
2016717Sgblack@eecs.umich.edu    }
2026734Sgblack@eecs.umich.edu
2036717Sgblack@eecs.umich.edu    void anRq(std::string sm, std::string q, int num = 1) {
2046717Sgblack@eecs.umich.edu        cpa->hwRq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
2056717Sgblack@eecs.umich.edu    }
2066717Sgblack@eecs.umich.edu
2076717Sgblack@eecs.umich.edu    void anWe(std::string sm, std::string q) {
2086717Sgblack@eecs.umich.edu        cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
2096717Sgblack@eecs.umich.edu    }
2106717Sgblack@eecs.umich.edu
2116717Sgblack@eecs.umich.edu    void anWf(std::string sm, std::string q) {
2126717Sgblack@eecs.umich.edu        cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
2136717Sgblack@eecs.umich.edu    }
2146717Sgblack@eecs.umich.edu
2156717Sgblack@eecs.umich.edu
2166717Sgblack@eecs.umich.edu    template<class T>
2176717Sgblack@eecs.umich.edu    class DescCache
2186717Sgblack@eecs.umich.edu    {
2196734Sgblack@eecs.umich.edu      protected:
2206717Sgblack@eecs.umich.edu        virtual Addr descBase() const = 0;
2216717Sgblack@eecs.umich.edu        virtual long descHead() const = 0;
2226717Sgblack@eecs.umich.edu        virtual long descTail() const = 0;
2236717Sgblack@eecs.umich.edu        virtual long descLen() const = 0;
2246717Sgblack@eecs.umich.edu        virtual void updateHead(long h) = 0;
2256717Sgblack@eecs.umich.edu        virtual void enableSm() = 0;
2266717Sgblack@eecs.umich.edu        virtual void actionAfterWb() {}
2276717Sgblack@eecs.umich.edu        virtual void fetchAfterWb() = 0;
2286717Sgblack@eecs.umich.edu
2296717Sgblack@eecs.umich.edu        typedef std::deque<T *> CacheType;
2306717Sgblack@eecs.umich.edu        CacheType usedCache;
2316717Sgblack@eecs.umich.edu        CacheType unusedCache;
2326717Sgblack@eecs.umich.edu
2336717Sgblack@eecs.umich.edu        T *fetchBuf;
2346717Sgblack@eecs.umich.edu        T *wbBuf;
2356717Sgblack@eecs.umich.edu
2366734Sgblack@eecs.umich.edu        // Pointer to the device we cache for
2376717Sgblack@eecs.umich.edu        IGbE *igbe;
23810037SARM gem5 Developers
23910037SARM gem5 Developers        // Name of this  descriptor cache
24010037SARM gem5 Developers        std::string _name;
24110037SARM gem5 Developers
24210037SARM gem5 Developers        // How far we've cached
24310037SARM gem5 Developers        int cachePnt;
24410037SARM gem5 Developers
24510037SARM gem5 Developers        // The size of the descriptor cache
24610037SARM gem5 Developers        int size;
24710037SARM gem5 Developers
24810037SARM gem5 Developers        // How many descriptors we are currently fetching
24910037SARM gem5 Developers        int curFetching;
25010037SARM gem5 Developers
25110037SARM gem5 Developers        // How many descriptors we are currently writing back
25210037SARM gem5 Developers        int wbOut;
25310037SARM gem5 Developers
25410037SARM gem5 Developers        // if the we wrote back to the end of the descriptor ring and are going
25510037SARM gem5 Developers        // to have to wrap and write more
25610037SARM gem5 Developers        bool moreToWb;
2576717Sgblack@eecs.umich.edu
2586717Sgblack@eecs.umich.edu        // What the alignment is of the next descriptor writeback
2596717Sgblack@eecs.umich.edu        Addr wbAlignment;
2606717Sgblack@eecs.umich.edu
2616717Sgblack@eecs.umich.edu        /** The packet that is currently being dmad to memory if any */
2626717Sgblack@eecs.umich.edu        EthPacketPtr pktPtr;
2636717Sgblack@eecs.umich.edu
2646717Sgblack@eecs.umich.edu        /** Shortcut for DMA address translation */
2656717Sgblack@eecs.umich.edu        Addr pciToDma(Addr a) { return igbe->platform->pciToDma(a); }
2666717Sgblack@eecs.umich.edu
2676717Sgblack@eecs.umich.edu      public:
2686717Sgblack@eecs.umich.edu        /** Annotate sm*/
2696717Sgblack@eecs.umich.edu        std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
2706717Sgblack@eecs.umich.edu            annUsedDescQ, annUnusedCacheQ, annDescQ;
2716717Sgblack@eecs.umich.edu
2726734Sgblack@eecs.umich.edu        DescCache(IGbE *i, const std::string n, int s);
2736717Sgblack@eecs.umich.edu        virtual ~DescCache();
2746717Sgblack@eecs.umich.edu
2756717Sgblack@eecs.umich.edu        std::string name() { return _name; }
2766717Sgblack@eecs.umich.edu
2776717Sgblack@eecs.umich.edu        /** If the address/len/head change when we've got descriptors that are
2786717Sgblack@eecs.umich.edu         * dirty that is very bad. This function checks that we don't and if we
2796717Sgblack@eecs.umich.edu         * do panics.
2806717Sgblack@eecs.umich.edu         */
2816717Sgblack@eecs.umich.edu        void areaChanged();
2826717Sgblack@eecs.umich.edu
2836717Sgblack@eecs.umich.edu        void writeback(Addr aMask);
2846717Sgblack@eecs.umich.edu        void writeback1();
2856717Sgblack@eecs.umich.edu        EventWrapper<DescCache, &DescCache::writeback1> wbDelayEvent;
2866717Sgblack@eecs.umich.edu
2876717Sgblack@eecs.umich.edu        /** Fetch a chunk of descriptors into the descriptor cache.
2886717Sgblack@eecs.umich.edu         * Calls fetchComplete when the memory system returns the data
2896734Sgblack@eecs.umich.edu         */
2906717Sgblack@eecs.umich.edu        void fetchDescriptors();
2916717Sgblack@eecs.umich.edu        void fetchDescriptors1();
2926717Sgblack@eecs.umich.edu        EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
2936717Sgblack@eecs.umich.edu
2946717Sgblack@eecs.umich.edu        /** Called by event when dma to read descriptors is completed
2956717Sgblack@eecs.umich.edu         */
2966717Sgblack@eecs.umich.edu        void fetchComplete();
2976717Sgblack@eecs.umich.edu        EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
2986717Sgblack@eecs.umich.edu
2996717Sgblack@eecs.umich.edu        /** Called by event when dma to writeback descriptors is completed
3006717Sgblack@eecs.umich.edu         */
3018902Sandreas.hansson@arm.com        void wbComplete();
3026717Sgblack@eecs.umich.edu        EventWrapper<DescCache, &DescCache::wbComplete> wbEvent;
3036717Sgblack@eecs.umich.edu
3046717Sgblack@eecs.umich.edu        /* Return the number of descriptors left in the ring, so the device has
3056717Sgblack@eecs.umich.edu         * a way to figure out if it needs to interrupt.
30610037SARM gem5 Developers         */
30710037SARM gem5 Developers        unsigned
30810037SARM gem5 Developers        descLeft() const
30910037SARM gem5 Developers        {
31010037SARM gem5 Developers            unsigned left = unusedCache.size();
31110037SARM gem5 Developers            if (cachePnt > descTail())
31210037SARM gem5 Developers                left += (descLen() - cachePnt + descTail());
31310037SARM gem5 Developers            else
31410037SARM gem5 Developers                left += (descTail() - cachePnt);
31510037SARM gem5 Developers
31610037SARM gem5 Developers            return left;
3176717Sgblack@eecs.umich.edu        }
3186717Sgblack@eecs.umich.edu
3196717Sgblack@eecs.umich.edu        /* Return the number of descriptors used and not written back.
3206717Sgblack@eecs.umich.edu         */
32110037SARM gem5 Developers        unsigned descUsed() const { return usedCache.size(); }
32210037SARM gem5 Developers
32310037SARM gem5 Developers        /* Return the number of cache unused descriptors we have. */
32410037SARM gem5 Developers        unsigned descUnused() const { return unusedCache.size(); }
32510037SARM gem5 Developers
3266717Sgblack@eecs.umich.edu        /* Get into a state where the descriptor address/head/etc colud be
3276717Sgblack@eecs.umich.edu         * changed */
3286717Sgblack@eecs.umich.edu        void reset();
3296717Sgblack@eecs.umich.edu
3306717Sgblack@eecs.umich.edu        virtual void serialize(std::ostream &os);
3316717Sgblack@eecs.umich.edu        virtual void unserialize(Checkpoint *cp, const std::string &section);
3326717Sgblack@eecs.umich.edu
3336717Sgblack@eecs.umich.edu        virtual bool hasOutstandingEvents() {
3346717Sgblack@eecs.umich.edu            return wbEvent.scheduled() || fetchEvent.scheduled();
33510037SARM gem5 Developers        }
33610037SARM gem5 Developers
33710037SARM gem5 Developers    };
33810037SARM gem5 Developers
33910037SARM gem5 Developers
34010037SARM gem5 Developers    class RxDescCache : public DescCache<iGbReg::RxDesc>
34110037SARM gem5 Developers    {
34210037SARM gem5 Developers      protected:
34310037SARM gem5 Developers        virtual Addr descBase() const { return igbe->regs.rdba(); }
34410037SARM gem5 Developers        virtual long descHead() const { return igbe->regs.rdh(); }
34510037SARM gem5 Developers        virtual long descLen() const { return igbe->regs.rdlen() >> 4; }
34610037SARM gem5 Developers        virtual long descTail() const { return igbe->regs.rdt(); }
34710037SARM gem5 Developers        virtual void updateHead(long h) { igbe->regs.rdh(h); }
34810037SARM gem5 Developers        virtual void enableSm();
34910037SARM gem5 Developers        virtual void fetchAfterWb() {
35010037SARM gem5 Developers            if (!igbe->rxTick && igbe->getState() == SimObject::Running)
35110037SARM gem5 Developers                fetchDescriptors();
35210037SARM gem5 Developers        }
3536717Sgblack@eecs.umich.edu
3546717Sgblack@eecs.umich.edu        bool pktDone;
3556717Sgblack@eecs.umich.edu
3566717Sgblack@eecs.umich.edu        /** Variable to head with header/data completion events */
35710037SARM gem5 Developers        int splitCount;
35810037SARM gem5 Developers
35910037SARM gem5 Developers        /** Bytes of packet that have been copied, so we know when to
36010037SARM gem5 Developers            set EOP */
36110037SARM gem5 Developers        unsigned bytesCopied;
3626717Sgblack@eecs.umich.edu
3636717Sgblack@eecs.umich.edu      public:
3646717Sgblack@eecs.umich.edu        RxDescCache(IGbE *i, std::string n, int s);
3656717Sgblack@eecs.umich.edu
3666717Sgblack@eecs.umich.edu        /** Write the given packet into the buffer(s) pointed to by the
3676717Sgblack@eecs.umich.edu         * descriptor and update the book keeping. Should only be called when
3686717Sgblack@eecs.umich.edu         * there are no dma's pending.
3696717Sgblack@eecs.umich.edu         * @param packet ethernet packet to write
3706717Sgblack@eecs.umich.edu         * @param pkt_offset bytes already copied from the packet to memory
3716717Sgblack@eecs.umich.edu         * @return pkt_offset + number of bytes copied during this call
3726717Sgblack@eecs.umich.edu         */
3736717Sgblack@eecs.umich.edu        int writePacket(EthPacketPtr packet, int pkt_offset);
3746717Sgblack@eecs.umich.edu
37510037SARM gem5 Developers        /** Called by event when dma to write packet is completed
37610037SARM gem5 Developers         */
37710037SARM gem5 Developers        void pktComplete();
37810037SARM gem5 Developers
37910037SARM gem5 Developers        /** Check if the dma on the packet has completed and RX state machine
3806717Sgblack@eecs.umich.edu         * can continue
3816717Sgblack@eecs.umich.edu         */
3826717Sgblack@eecs.umich.edu        bool packetDone();
3836717Sgblack@eecs.umich.edu
3846717Sgblack@eecs.umich.edu        EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
3856717Sgblack@eecs.umich.edu
3866717Sgblack@eecs.umich.edu        // Event to handle issuing header and data write at the same time
3876717Sgblack@eecs.umich.edu        // and only callking pktComplete() when both are completed
3886717Sgblack@eecs.umich.edu        void pktSplitDone();
3896717Sgblack@eecs.umich.edu        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent;
3906717Sgblack@eecs.umich.edu        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent;
3916717Sgblack@eecs.umich.edu
3926717Sgblack@eecs.umich.edu        virtual bool hasOutstandingEvents();
39310037SARM gem5 Developers
39410037SARM gem5 Developers        virtual void serialize(std::ostream &os);
39510037SARM gem5 Developers        virtual void unserialize(Checkpoint *cp, const std::string &section);
39610037SARM gem5 Developers    };
39710037SARM gem5 Developers    friend class RxDescCache;
3986717Sgblack@eecs.umich.edu
3996717Sgblack@eecs.umich.edu    RxDescCache rxDescCache;
4006717Sgblack@eecs.umich.edu
4016717Sgblack@eecs.umich.edu    class TxDescCache  : public DescCache<iGbReg::TxDesc>
4026717Sgblack@eecs.umich.edu    {
4036717Sgblack@eecs.umich.edu      protected:
4046717Sgblack@eecs.umich.edu        virtual Addr descBase() const { return igbe->regs.tdba(); }
4056717Sgblack@eecs.umich.edu        virtual long descHead() const { return igbe->regs.tdh(); }
4066717Sgblack@eecs.umich.edu        virtual long descTail() const { return igbe->regs.tdt(); }
4076717Sgblack@eecs.umich.edu        virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
4086717Sgblack@eecs.umich.edu        virtual void updateHead(long h) { igbe->regs.tdh(h); }
4096717Sgblack@eecs.umich.edu        virtual void enableSm();
4106717Sgblack@eecs.umich.edu        virtual void actionAfterWb();
41110037SARM gem5 Developers        virtual void fetchAfterWb() {
41210037SARM gem5 Developers            if (!igbe->txTick && igbe->getState() == SimObject::Running)
41310037SARM gem5 Developers                fetchDescriptors();
41410037SARM gem5 Developers        }
41510037SARM gem5 Developers
4166717Sgblack@eecs.umich.edu
4176717Sgblack@eecs.umich.edu
4186717Sgblack@eecs.umich.edu        bool pktDone;
4196717Sgblack@eecs.umich.edu        bool isTcp;
4206717Sgblack@eecs.umich.edu        bool pktWaiting;
4216717Sgblack@eecs.umich.edu        bool pktMultiDesc;
4226717Sgblack@eecs.umich.edu        Addr completionAddress;
4236717Sgblack@eecs.umich.edu        bool completionEnabled;
4246717Sgblack@eecs.umich.edu        uint32_t descEnd;
4256717Sgblack@eecs.umich.edu
4266717Sgblack@eecs.umich.edu
4276717Sgblack@eecs.umich.edu        // tso variables
4286717Sgblack@eecs.umich.edu        bool useTso;
42910037SARM gem5 Developers        Addr tsoHeaderLen;
43010037SARM gem5 Developers        Addr tsoMss;
43110037SARM gem5 Developers        Addr tsoTotalLen;
43210037SARM gem5 Developers        Addr tsoUsedLen;
43310037SARM gem5 Developers        Addr tsoPrevSeq;
4346717Sgblack@eecs.umich.edu        Addr tsoPktPayloadBytes;
4356717Sgblack@eecs.umich.edu        bool tsoLoadedHeader;
4366717Sgblack@eecs.umich.edu        bool tsoPktHasHeader;
4376717Sgblack@eecs.umich.edu        uint8_t tsoHeader[256];
4386717Sgblack@eecs.umich.edu        Addr tsoDescBytesUsed;
4396717Sgblack@eecs.umich.edu        Addr tsoCopyBytes;
4406717Sgblack@eecs.umich.edu        int tsoPkts;
4416717Sgblack@eecs.umich.edu
4426717Sgblack@eecs.umich.edu      public:
4436717Sgblack@eecs.umich.edu        TxDescCache(IGbE *i, std::string n, int s);
4446717Sgblack@eecs.umich.edu
4456717Sgblack@eecs.umich.edu        /** Tell the cache to DMA a packet from main memory into its buffer and
4466717Sgblack@eecs.umich.edu         * return the size the of the packet to reserve space in tx fifo.
44710037SARM gem5 Developers         * @return size of the packet
44810037SARM gem5 Developers         */
44910037SARM gem5 Developers        unsigned getPacketSize(EthPacketPtr p);
45010037SARM gem5 Developers        void getPacketData(EthPacketPtr p);
45110037SARM gem5 Developers        void processContextDesc();
4526717Sgblack@eecs.umich.edu
4536717Sgblack@eecs.umich.edu        /** Return the number of dsecriptors in a cache block for threshold
4546717Sgblack@eecs.umich.edu         * operations.
4556717Sgblack@eecs.umich.edu         */
4566717Sgblack@eecs.umich.edu        unsigned
4576717Sgblack@eecs.umich.edu        descInBlock(unsigned num_desc)
4586717Sgblack@eecs.umich.edu        {
4596717Sgblack@eecs.umich.edu            return num_desc / igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc);
4606717Sgblack@eecs.umich.edu        }
4617310Sgblack@eecs.umich.edu
4627310Sgblack@eecs.umich.edu        /** Ask if the packet has been transfered so the state machine can give
4637310Sgblack@eecs.umich.edu         * it to the fifo.
4647310Sgblack@eecs.umich.edu         * @return packet available in descriptor cache
4656726Sgblack@eecs.umich.edu         */
4667310Sgblack@eecs.umich.edu        bool packetAvailable();
4677310Sgblack@eecs.umich.edu
4686726Sgblack@eecs.umich.edu        /** Ask if we are still waiting for the packet to be transfered.
4696726Sgblack@eecs.umich.edu         * @return packet still in transit.
47010037SARM gem5 Developers         */
47110037SARM gem5 Developers        bool packetWaiting() { return pktWaiting; }
47210037SARM gem5 Developers
47310037SARM gem5 Developers        /** Ask if this packet is composed of multiple descriptors
47410037SARM gem5 Developers         * so even if we've got data, we need to wait for more before
47510037SARM gem5 Developers         * we can send it out.
47610037SARM gem5 Developers         * @return packet can't be sent out because it's a multi-descriptor
47710037SARM gem5 Developers         * packet
47810037SARM gem5 Developers         */
47910037SARM gem5 Developers        bool packetMultiDesc() { return pktMultiDesc;}
48010037SARM gem5 Developers
48110037SARM gem5 Developers        /** Called by event when dma to write packet is completed
48210037SARM gem5 Developers         */
48310037SARM gem5 Developers        void pktComplete();
48410037SARM gem5 Developers        EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
48510037SARM gem5 Developers
48610037SARM gem5 Developers        void headerComplete();
48710037SARM gem5 Developers        EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
48810037SARM gem5 Developers
48910037SARM gem5 Developers
49010037SARM gem5 Developers        void completionWriteback(Addr a, bool enabled) {
49110037SARM gem5 Developers            DPRINTF(EthernetDesc,
49210037SARM gem5 Developers                    "Completion writeback Addr: %#x enabled: %d\n",
49310037SARM gem5 Developers                    a, enabled);
49410037SARM gem5 Developers            completionAddress = a;
49510037SARM gem5 Developers            completionEnabled = enabled;
49610037SARM gem5 Developers        }
49710037SARM gem5 Developers
49810037SARM gem5 Developers        virtual bool hasOutstandingEvents();
49910037SARM gem5 Developers
50010037SARM gem5 Developers        void nullCallback() {
50110037SARM gem5 Developers            DPRINTF(EthernetDesc, "Completion writeback complete\n");
50210037SARM gem5 Developers        }
50310037SARM gem5 Developers        EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
50410037SARM gem5 Developers
50510037SARM gem5 Developers        virtual void serialize(std::ostream &os);
50610037SARM gem5 Developers        virtual void unserialize(Checkpoint *cp, const std::string &section);
50710037SARM gem5 Developers
50810337SAndrew.Bardsley@arm.com    };
50910337SAndrew.Bardsley@arm.com    friend class TxDescCache;
51010337SAndrew.Bardsley@arm.com
51110337SAndrew.Bardsley@arm.com    TxDescCache txDescCache;
51210337SAndrew.Bardsley@arm.com
51310337SAndrew.Bardsley@arm.com  public:
51410337SAndrew.Bardsley@arm.com    typedef IGbEParams Params;
51510037SARM gem5 Developers    const Params *
51610037SARM gem5 Developers    params() const {
51710037SARM gem5 Developers        return dynamic_cast<const Params *>(_params);
51810037SARM gem5 Developers    }
51910037SARM gem5 Developers
52010037SARM gem5 Developers    IGbE(const Params *params);
52110037SARM gem5 Developers    ~IGbE() {}
5226717Sgblack@eecs.umich.edu    virtual void init();
5236717Sgblack@eecs.umich.edu
5246717Sgblack@eecs.umich.edu    virtual EtherInt *getEthPort(const std::string &if_name, int idx);
525
526    Tick clock;
527    Tick lastInterrupt;
528    inline Tick ticks(int numCycles) const { return numCycles * clock; }
529
530    virtual Tick read(PacketPtr pkt);
531    virtual Tick write(PacketPtr pkt);
532
533    virtual Tick writeConfig(PacketPtr pkt);
534
535    bool ethRxPkt(EthPacketPtr packet);
536    void ethTxDone();
537
538    virtual void serialize(std::ostream &os);
539    virtual void unserialize(Checkpoint *cp, const std::string &section);
540    virtual unsigned int drain(Event *de);
541    virtual void resume();
542
543};
544
545class IGbEInt : public EtherInt
546{
547  private:
548    IGbE *dev;
549
550  public:
551    IGbEInt(const std::string &name, IGbE *d)
552        : EtherInt(name), dev(d)
553    { }
554
555    virtual bool recvPacket(EthPacketPtr pkt) { return dev->ethRxPkt(pkt); }
556    virtual void sendDone() { dev->ethTxDone(); }
557};
558
559#endif //__DEV_I8254XGBE_HH__
560