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 §ion) 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 §ion); 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 §ion); 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 §ion); 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