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 + -
显示快捷键?