io_device.hh revision 5534
12568SN/A/* 22568SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 32568SN/A * All rights reserved. 42568SN/A * 52568SN/A * Redistribution and use in source and binary forms, with or without 62568SN/A * modification, are permitted provided that the following conditions are 72568SN/A * met: redistributions of source code must retain the above copyright 82568SN/A * notice, this list of conditions and the following disclaimer; 92568SN/A * redistributions in binary form must reproduce the above copyright 102568SN/A * notice, this list of conditions and the following disclaimer in the 112568SN/A * documentation and/or other materials provided with the distribution; 122568SN/A * neither the name of the copyright holders nor the names of its 132568SN/A * contributors may be used to endorse or promote products derived from 142568SN/A * this software without specific prior written permission. 152568SN/A * 162568SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172568SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182568SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192568SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202568SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212568SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222568SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232568SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242568SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252568SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262568SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272568SN/A * 282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi 292665Ssaidi@eecs.umich.edu * Nathan Binkert 302665Ssaidi@eecs.umich.edu */ 312568SN/A 322568SN/A#ifndef __DEV_IO_DEVICE_HH__ 332568SN/A#define __DEV_IO_DEVICE_HH__ 342982Sstever@eecs.umich.edu 352982Sstever@eecs.umich.edu#include "base/fast_alloc.hh" 362568SN/A#include "mem/mem_object.hh" 372568SN/A#include "mem/packet.hh" 382643Sstever@eecs.umich.edu#include "mem/tport.hh" 392568SN/A#include "params/BasicPioDevice.hh" 402568SN/A#include "params/DmaDevice.hh" 412568SN/A#include "params/PioDevice.hh" 424762Snate@binkert.org#include "sim/sim_object.hh" 432568SN/A 442643Sstever@eecs.umich.educlass Event; 452643Sstever@eecs.umich.educlass Platform; 464435Ssaidi@eecs.umich.educlass PioDevice; 474435Ssaidi@eecs.umich.educlass DmaDevice; 482643Sstever@eecs.umich.educlass System; 494435Ssaidi@eecs.umich.edu 504435Ssaidi@eecs.umich.edu/** 514435Ssaidi@eecs.umich.edu * The PioPort class is a programmed i/o port that all devices that are 522643Sstever@eecs.umich.edu * sensitive to an address range use. The port takes all the memory 532643Sstever@eecs.umich.edu * access types and roles them into one read() and write() call that the device 542643Sstever@eecs.umich.edu * must respond to. The device must also provide the addressRanges() function 554435Ssaidi@eecs.umich.edu * with which it returns the address ranges it is interested in. 564435Ssaidi@eecs.umich.edu */ 574435Ssaidi@eecs.umich.educlass PioPort : public SimpleTimingPort 584435Ssaidi@eecs.umich.edu{ 594435Ssaidi@eecs.umich.edu protected: 604435Ssaidi@eecs.umich.edu /** The device that this port serves. */ 614435Ssaidi@eecs.umich.edu PioDevice *device; 622643Sstever@eecs.umich.edu 634432Ssaidi@eecs.umich.edu virtual Tick recvAtomic(PacketPtr pkt); 644432Ssaidi@eecs.umich.edu 652643Sstever@eecs.umich.edu virtual void getDeviceAddressRanges(AddrRangeList &resp, 662643Sstever@eecs.umich.edu bool &snoop); 672643Sstever@eecs.umich.edu 682738Sstever@eecs.umich.edu public: 692643Sstever@eecs.umich.edu 702643Sstever@eecs.umich.edu PioPort(PioDevice *dev, System *s, std::string pname = "-pioport"); 712643Sstever@eecs.umich.edu}; 722643Sstever@eecs.umich.edu 732643Sstever@eecs.umich.edu 742643Sstever@eecs.umich.educlass DmaPort : public Port 752643Sstever@eecs.umich.edu{ 762643Sstever@eecs.umich.edu protected: 772643Sstever@eecs.umich.edu struct DmaReqState : public Packet::SenderState, public FastAlloc 782643Sstever@eecs.umich.edu { 792643Sstever@eecs.umich.edu /** Event to call on the device when this transaction (all packets) 802643Sstever@eecs.umich.edu * complete. */ 812643Sstever@eecs.umich.edu Event *completionEvent; 822643Sstever@eecs.umich.edu 832643Sstever@eecs.umich.edu /** Where we came from for some sanity checking. */ 842643Sstever@eecs.umich.edu Port *outPort; 852568SN/A 862568SN/A /** Total number of bytes that this transaction involves. */ 872568SN/A Addr totBytes; 882568SN/A 892643Sstever@eecs.umich.edu /** Number of bytes that have been acked for this transaction. */ 904432Ssaidi@eecs.umich.edu Addr numBytes; 914432Ssaidi@eecs.umich.edu 924432Ssaidi@eecs.umich.edu /** Amount to delay completion of dma by */ 934432Ssaidi@eecs.umich.edu Tick delay; 942568SN/A 952568SN/A DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay) 964433Ssaidi@eecs.umich.edu : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0), 974435Ssaidi@eecs.umich.edu delay(_delay) 984433Ssaidi@eecs.umich.edu {} 994435Ssaidi@eecs.umich.edu }; 1004435Ssaidi@eecs.umich.edu 1014435Ssaidi@eecs.umich.edu DmaDevice *device; 1024435Ssaidi@eecs.umich.edu std::list<PacketPtr> transmitList; 1034435Ssaidi@eecs.umich.edu 1044435Ssaidi@eecs.umich.edu /** The system that device/port are in. This is used to select which mode 1054435Ssaidi@eecs.umich.edu * we are currently operating in. */ 1064435Ssaidi@eecs.umich.edu System *sys; 1074435Ssaidi@eecs.umich.edu 1084433Ssaidi@eecs.umich.edu /** Number of outstanding packets the dma port has. */ 1092568SN/A int pendingCount; 1102643Sstever@eecs.umich.edu 1112568SN/A /** If a dmaAction is in progress. */ 1122568SN/A int actionInProgress; 1133349Sbinkertn@umich.edu 1142568SN/A /** If we need to drain, keep the drain event around until we're done 1154433Ssaidi@eecs.umich.edu * here.*/ 1164433Ssaidi@eecs.umich.edu Event *drainEvent; 1174433Ssaidi@eecs.umich.edu 1184433Ssaidi@eecs.umich.edu /** time to wait between sending another packet, increases as NACKs are 1194433Ssaidi@eecs.umich.edu * recived, decreases as responses are recived. */ 1203662Srdreslin@umich.edu Tick backoffTime; 1212643Sstever@eecs.umich.edu 1224450Ssaidi@eecs.umich.edu /** If the port is currently waiting for a retry before it can send whatever 1234450Ssaidi@eecs.umich.edu * it is that it's sending. */ 1244450Ssaidi@eecs.umich.edu bool inRetry; 1254450Ssaidi@eecs.umich.edu 1264450Ssaidi@eecs.umich.edu virtual bool recvTiming(PacketPtr pkt); 1274450Ssaidi@eecs.umich.edu virtual Tick recvAtomic(PacketPtr pkt) 1284450Ssaidi@eecs.umich.edu { panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN } 1294450Ssaidi@eecs.umich.edu virtual void recvFunctional(PacketPtr pkt) 1304433Ssaidi@eecs.umich.edu { panic("dma port shouldn't be used for pio access."); } 1314433Ssaidi@eecs.umich.edu 1324433Ssaidi@eecs.umich.edu virtual void recvStatusChange(Status status) 1333662Srdreslin@umich.edu { ; } 1344433Ssaidi@eecs.umich.edu 1354433Ssaidi@eecs.umich.edu virtual void recvRetry() ; 1364435Ssaidi@eecs.umich.edu 1374433Ssaidi@eecs.umich.edu virtual void getDeviceAddressRanges(AddrRangeList &resp, 1384433Ssaidi@eecs.umich.edu bool &snoop) 1394433Ssaidi@eecs.umich.edu { resp.clear(); snoop = false; } 1404433Ssaidi@eecs.umich.edu 1414433Ssaidi@eecs.umich.edu void queueDma(PacketPtr pkt, bool front = false); 1424433Ssaidi@eecs.umich.edu void sendDma(); 1434433Ssaidi@eecs.umich.edu 1444433Ssaidi@eecs.umich.edu /** event to give us a kick every time we backoff time is reached. */ 1454433Ssaidi@eecs.umich.edu EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent; 1464433Ssaidi@eecs.umich.edu 1474433Ssaidi@eecs.umich.edu public: 1484433Ssaidi@eecs.umich.edu DmaPort(DmaDevice *dev, System *s); 1494433Ssaidi@eecs.umich.edu 1502657Ssaidi@eecs.umich.edu void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 1512657Ssaidi@eecs.umich.edu uint8_t *data, Tick delay); 1524433Ssaidi@eecs.umich.edu 1534433Ssaidi@eecs.umich.edu bool dmaPending() { return pendingCount > 0; } 1544433Ssaidi@eecs.umich.edu 1554433Ssaidi@eecs.umich.edu int cacheBlockSize() { return peerBlockSize(); } 1564433Ssaidi@eecs.umich.edu unsigned int drain(Event *de); 1574433Ssaidi@eecs.umich.edu}; 1582657Ssaidi@eecs.umich.edu 1594433Ssaidi@eecs.umich.edu/** 1604435Ssaidi@eecs.umich.edu * This device is the base class which all devices senstive to an address range 1614433Ssaidi@eecs.umich.edu * inherit from. There are three pure virtual functions which all devices must 1624435Ssaidi@eecs.umich.edu * implement addressRanges(), read(), and write(). The magic do choose which 1634435Ssaidi@eecs.umich.edu * mode we are in, etc is handled by the PioPort so the device doesn't have to 1644433Ssaidi@eecs.umich.edu * bother. 1654435Ssaidi@eecs.umich.edu */ 1664433Ssaidi@eecs.umich.educlass PioDevice : public MemObject 1674435Ssaidi@eecs.umich.edu{ 1684435Ssaidi@eecs.umich.edu protected: 1694433Ssaidi@eecs.umich.edu 1704435Ssaidi@eecs.umich.edu /** The platform we are in. This is used to decide what type of memory 1714435Ssaidi@eecs.umich.edu * transaction we should perform. */ 1724435Ssaidi@eecs.umich.edu Platform *platform; 1734435Ssaidi@eecs.umich.edu 1744435Ssaidi@eecs.umich.edu System *sys; 1754435Ssaidi@eecs.umich.edu 1764435Ssaidi@eecs.umich.edu /** The pioPort that handles the requests for us and provides us requests 1774435Ssaidi@eecs.umich.edu * that it sees. */ 1784435Ssaidi@eecs.umich.edu PioPort *pioPort; 1794435Ssaidi@eecs.umich.edu 1804435Ssaidi@eecs.umich.edu virtual void addressRanges(AddrRangeList &range_list) = 0; 1814435Ssaidi@eecs.umich.edu 1824435Ssaidi@eecs.umich.edu /** Pure virtual function that the device must implement. Called 1834435Ssaidi@eecs.umich.edu * when a read command is recieved by the port. 1844435Ssaidi@eecs.umich.edu * @param pkt Packet describing this request 1854435Ssaidi@eecs.umich.edu * @return number of ticks it took to complete 1864435Ssaidi@eecs.umich.edu */ 1874435Ssaidi@eecs.umich.edu virtual Tick read(PacketPtr pkt) = 0; 1884435Ssaidi@eecs.umich.edu 1894435Ssaidi@eecs.umich.edu /** Pure virtual function that the device must implement. Called when a 1904435Ssaidi@eecs.umich.edu * write command is recieved by the port. 1914435Ssaidi@eecs.umich.edu * @param pkt Packet describing this request 1924435Ssaidi@eecs.umich.edu * @return number of ticks it took to complete 1934435Ssaidi@eecs.umich.edu */ 1944435Ssaidi@eecs.umich.edu virtual Tick write(PacketPtr pkt) = 0; 1954433Ssaidi@eecs.umich.edu 1964433Ssaidi@eecs.umich.edu public: 1974433Ssaidi@eecs.umich.edu typedef PioDeviceParams Params; 1984433Ssaidi@eecs.umich.edu PioDevice(const Params *p); 1993349Sbinkertn@umich.edu virtual ~PioDevice(); 2002657Ssaidi@eecs.umich.edu 2014450Ssaidi@eecs.umich.edu const Params * 2022643Sstever@eecs.umich.edu params() const 2032643Sstever@eecs.umich.edu { 2042643Sstever@eecs.umich.edu return dynamic_cast<const Params *>(_params); 2052643Sstever@eecs.umich.edu } 2062643Sstever@eecs.umich.edu 2072643Sstever@eecs.umich.edu virtual void init(); 2082643Sstever@eecs.umich.edu 2092643Sstever@eecs.umich.edu virtual unsigned int drain(Event *de); 2104433Ssaidi@eecs.umich.edu 2114450Ssaidi@eecs.umich.edu virtual Port *getPort(const std::string &if_name, int idx = -1) 2124450Ssaidi@eecs.umich.edu { 2134450Ssaidi@eecs.umich.edu if (if_name == "pio") { 2144433Ssaidi@eecs.umich.edu if (pioPort != NULL) 2154433Ssaidi@eecs.umich.edu panic("pio port already connected to."); 2164739Sstever@eecs.umich.edu pioPort = new PioPort(this, sys); 2172643Sstever@eecs.umich.edu return pioPort; 2182643Sstever@eecs.umich.edu } else 2192643Sstever@eecs.umich.edu return NULL; 2204450Ssaidi@eecs.umich.edu } 2214450Ssaidi@eecs.umich.edu friend class PioPort; 2224450Ssaidi@eecs.umich.edu 2234450Ssaidi@eecs.umich.edu}; 2244450Ssaidi@eecs.umich.edu 2254450Ssaidi@eecs.umich.educlass BasicPioDevice : public PioDevice 2264450Ssaidi@eecs.umich.edu{ 2272643Sstever@eecs.umich.edu protected: 2282643Sstever@eecs.umich.edu /** Address that the device listens to. */ 2292643Sstever@eecs.umich.edu Addr pioAddr; 2302643Sstever@eecs.umich.edu 2312643Sstever@eecs.umich.edu /** Size that the device's address range. */ 2322643Sstever@eecs.umich.edu Addr pioSize; 2332643Sstever@eecs.umich.edu 2342643Sstever@eecs.umich.edu /** Delay that the device experinces on an access. */ 2352643Sstever@eecs.umich.edu Tick pioDelay; 2362568SN/A 2372643Sstever@eecs.umich.edu public: 2382568SN/A typedef BasicPioDeviceParams Params; 2392568SN/A BasicPioDevice(const Params *p); 2402568SN/A 2412643Sstever@eecs.umich.edu const Params * 2422568SN/A params() const 2432643Sstever@eecs.umich.edu { 2442568SN/A return dynamic_cast<const Params *>(_params); 2452643Sstever@eecs.umich.edu } 2462643Sstever@eecs.umich.edu 2472643Sstever@eecs.umich.edu /** return the address ranges that this device responds to. 2482643Sstever@eecs.umich.edu * @param range_list range list to populate with ranges 2493349Sbinkertn@umich.edu */ 2502643Sstever@eecs.umich.edu void addressRanges(AddrRangeList &range_list); 2514432Ssaidi@eecs.umich.edu 2524432Ssaidi@eecs.umich.edu}; 2534454Ssaidi@eecs.umich.edu 2544432Ssaidi@eecs.umich.educlass DmaDevice : public PioDevice 2554454Ssaidi@eecs.umich.edu{ 2564454Ssaidi@eecs.umich.edu protected: 2574454Ssaidi@eecs.umich.edu DmaPort *dmaPort; 2584454Ssaidi@eecs.umich.edu Tick minBackoffDelay; 2594454Ssaidi@eecs.umich.edu Tick maxBackoffDelay; 2604454Ssaidi@eecs.umich.edu 2614454Ssaidi@eecs.umich.edu public: 2624432Ssaidi@eecs.umich.edu typedef DmaDeviceParams Params; 2634432Ssaidi@eecs.umich.edu DmaDevice(const Params *p); 2642643Sstever@eecs.umich.edu virtual ~DmaDevice(); 2652643Sstever@eecs.umich.edu 2662643Sstever@eecs.umich.edu const Params * 2674450Ssaidi@eecs.umich.edu params() const 2684450Ssaidi@eecs.umich.edu { 2694432Ssaidi@eecs.umich.edu return dynamic_cast<const Params *>(_params); 2702643Sstever@eecs.umich.edu } 2712643Sstever@eecs.umich.edu 2722643Sstever@eecs.umich.edu void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0) 2732643Sstever@eecs.umich.edu { 2742657Ssaidi@eecs.umich.edu dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data, delay); 2752657Ssaidi@eecs.umich.edu } 2764433Ssaidi@eecs.umich.edu 2772657Ssaidi@eecs.umich.edu void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0) 2782657Ssaidi@eecs.umich.edu { 2792657Ssaidi@eecs.umich.edu dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data, delay); 2802657Ssaidi@eecs.umich.edu } 2812657Ssaidi@eecs.umich.edu 2822657Ssaidi@eecs.umich.edu bool dmaPending() { return dmaPort->dmaPending(); } 2832657Ssaidi@eecs.umich.edu 2842657Ssaidi@eecs.umich.edu virtual unsigned int drain(Event *de); 2854450Ssaidi@eecs.umich.edu 2864450Ssaidi@eecs.umich.edu int cacheBlockSize() { return dmaPort->cacheBlockSize(); } 2874433Ssaidi@eecs.umich.edu 2884450Ssaidi@eecs.umich.edu virtual Port *getPort(const std::string &if_name, int idx = -1) 2894450Ssaidi@eecs.umich.edu { 2904450Ssaidi@eecs.umich.edu if (if_name == "pio") { 2914433Ssaidi@eecs.umich.edu if (pioPort != NULL) 2922657Ssaidi@eecs.umich.edu panic("pio port already connected to."); 2932657Ssaidi@eecs.umich.edu pioPort = new PioPort(this, sys); 2942657Ssaidi@eecs.umich.edu return pioPort; 2954433Ssaidi@eecs.umich.edu } else if (if_name == "dma") { 2962657Ssaidi@eecs.umich.edu if (dmaPort != NULL) 2972657Ssaidi@eecs.umich.edu panic("dma port already connected to."); 2982643Sstever@eecs.umich.edu dmaPort = new DmaPort(this, sys); 2992643Sstever@eecs.umich.edu return dmaPort; 3004435Ssaidi@eecs.umich.edu } else 3012643Sstever@eecs.umich.edu return NULL; 3024433Ssaidi@eecs.umich.edu } 3034433Ssaidi@eecs.umich.edu 3042568SN/A friend class DmaPort; 3052568SN/A}; 3062568SN/A 3072657Ssaidi@eecs.umich.edu 3082568SN/A#endif // __DEV_IO_DEVICE_HH__ 3092568SN/A