i8254xgbe.hh

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 654 行 · 第 1/2 页

HH
654
字号
/* * Copyright (c) 2006 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Ali G. Saidi *//* @file * Device model for Intel's 8254x line of gigabit ethernet controllers. */#ifndef __DEV_I8254XGBE_HH__#define __DEV_I8254XGBE_HH__#include <deque>#include <string>#include "base/inet.hh"#include "base/statistics.hh"#include "dev/etherdevice.hh"#include "dev/etherint.hh"#include "dev/etherpkt.hh"#include "dev/i8254xGBe_defs.hh"#include "dev/pcidev.hh"#include "dev/pktfifo.hh"#include "params/IGbE.hh"#include "sim/eventq.hh"class IGbEInt;class IGbE : public EtherDevice{  private:    IGbEInt *etherInt;    // device registers    iGbReg::Regs regs;    // eeprom data, status and control bits    int eeOpBits, eeAddrBits, eeDataBits;    uint8_t eeOpcode, eeAddr;    uint16_t flash[iGbReg::EEPROM_SIZE];    // The drain event if we have one    Event *drainEvent;    // cached parameters from params struct    bool useFlowControl;    // packet fifos    PacketFifo rxFifo;    PacketFifo txFifo;    // Packet that we are currently putting into the txFifo    EthPacketPtr txPacket;    // Should to Rx/Tx State machine tick?    bool rxTick;    bool txTick;    bool txFifoTick;    bool rxDmaPacket;    // Event and function to deal with RDTR timer expiring    void rdtrProcess() {        rxDescCache.writeback(0);        DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n");        postInterrupt(iGbReg::IT_RXT, true);    }    //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;    EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;    // Event and function to deal with RADV timer expiring    void radvProcess() {        rxDescCache.writeback(0);        DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n");        postInterrupt(iGbReg::IT_RXT, true);    }    //friend class EventWrapper<IGbE, &IGbE::radvProcess>;    EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;    // Event and function to deal with TADV timer expiring    void tadvProcess() {        txDescCache.writeback(0);        DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n");        postInterrupt(iGbReg::IT_TXDW, true);    }    //friend class EventWrapper<IGbE, &IGbE::tadvProcess>;    EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent;    // Event and function to deal with TIDV timer expiring    void tidvProcess() {        txDescCache.writeback(0);        DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n");        postInterrupt(iGbReg::IT_TXDW, true);    }    //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;    EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;    // Main event to tick the device    void tick();    //friend class EventWrapper<IGbE, &IGbE::tick>;    EventWrapper<IGbE, &IGbE::tick> tickEvent;    void rxStateMachine();    void txStateMachine();    void txWire();    /** Write an interrupt into the interrupt pending register and check mask     * and interrupt limit timer before sending interrupt to CPU     * @param t the type of interrupt we are posting     * @param now should we ignore the interrupt limiting timer     */    void postInterrupt(iGbReg::IntTypes t, bool now = false);    /** Check and see if changes to the mask register have caused an interrupt     * to need to be sent or perhaps removed an interrupt cause.     */    void chkInterrupt();    /** Send an interrupt to the cpu     */    void delayIntEvent();    void cpuPostInt();    // Event to moderate interrupts    EventWrapper<IGbE, &IGbE::delayIntEvent> interEvent;    /** Clear the interupt line to the cpu     */    void cpuClearInt();    Tick intClock() { return Clock::Int::ns * 1024; }    /** This function is used to restart the clock so it can handle things like     * draining and resume in one place. */    void restartClock();    /** Check if all the draining things that need to occur have occured and     * handle the drain event if so.     */    void checkDrain();    template<class T>    class DescCache    {      protected:        virtual Addr descBase() const = 0;        virtual long descHead() const = 0;        virtual long descTail() const = 0;        virtual long descLen() const = 0;        virtual void updateHead(long h) = 0;        virtual void enableSm() = 0;        virtual void intAfterWb() const {}        virtual void fetchAfterWb() = 0;        std::deque<T*> usedCache;        std::deque<T*> unusedCache;        T *fetchBuf;        T *wbBuf;        // Pointer to the device we cache for        IGbE *igbe;        // Name of this  descriptor cache        std::string _name;        // How far we've cached        int cachePnt;        // The size of the descriptor cache        int size;        // How many descriptors we are currently fetching        int curFetching;        // How many descriptors we are currently writing back        int wbOut;        // if the we wrote back to the end of the descriptor ring and are going        // to have to wrap and write more        bool moreToWb;        // What the alignment is of the next descriptor writeback        Addr wbAlignment;       /** The packet that is currently being dmad to memory if any         */        EthPacketPtr pktPtr;      public:        DescCache(IGbE *i, const std::string n, int s)            : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0),              pktPtr(NULL), fetchEvent(this), wbEvent(this)        {            fetchBuf = new T[size];            wbBuf = new T[size];        }        virtual ~DescCache()        {            reset();        }        std::string name() { return _name; }        /** If the address/len/head change when we've got descriptors that are         * 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 writeback(Addr aMask)        {            int curHead = descHead();            int max_to_wb = usedCache.size();            DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "                    "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",                    curHead, descTail(), descLen(), cachePnt, max_to_wb,                    descLeft());            // Check if this writeback is less restrictive that the previous            // and if so setup another one immediately following it            if (wbOut && (aMask < wbAlignment)) {                moreToWb = true;                wbAlignment = aMask;                DPRINTF(EthernetDesc, "Writing back already in process, returning\n");                return;            }            moreToWb = false;            wbAlignment = aMask;            if (max_to_wb + curHead >= descLen()) {                max_to_wb = descLen() - curHead;                moreToWb = true;                // this is by definition aligned correctly            } else if (aMask != 0) {                // align the wb point to the mask                max_to_wb = max_to_wb & ~aMask;            }            DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);            if (max_to_wb <= 0 || wbOut)                return;            wbOut = max_to_wb;            for (int x = 0; x < wbOut; x++) {                assert(usedCache.size());                memcpy(&wbBuf[x], usedCache[0], sizeof(T));                delete usedCache[0];                usedCache.pop_front();            }            assert(wbOut);            igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)),                    wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf);        }        /** 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)                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;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?