io_device.hh revision 4475
12391SN/A/* 28931Sandreas.hansson@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 37733SN/A * All rights reserved. 47733SN/A * 57733SN/A * Redistribution and use in source and binary forms, with or without 67733SN/A * modification, are permitted provided that the following conditions are 77733SN/A * met: redistributions of source code must retain the above copyright 87733SN/A * notice, this list of conditions and the following disclaimer; 97733SN/A * redistributions in binary form must reproduce the above copyright 107733SN/A * notice, this list of conditions and the following disclaimer in the 117733SN/A * documentation and/or other materials provided with the distribution; 127733SN/A * neither the name of the copyright holders nor the names of its 137733SN/A * contributors may be used to endorse or promote products derived from 142391SN/A * this software without specific prior written permission. 152391SN/A * 162391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272391SN/A * 282391SN/A * Authors: Ali Saidi 292391SN/A * Nathan Binkert 302391SN/A */ 312391SN/A 322391SN/A#ifndef __DEV_IO_DEVICE_HH__ 332391SN/A#define __DEV_IO_DEVICE_HH__ 342391SN/A 352391SN/A#include "mem/mem_object.hh" 362391SN/A#include "mem/packet.hh" 372391SN/A#include "mem/tport.hh" 382391SN/A#include "sim/sim_object.hh" 392665SN/A 402665SN/Aclass Event; 412914SN/Aclass Platform; 428931Sandreas.hansson@arm.comclass PioDevice; 432391SN/Aclass DmaDevice; 442391SN/Aclass System; 458229SN/A 462391SN/A/** 477730SN/A * The PioPort class is a programmed i/o port that all devices that are 482391SN/A * sensitive to an address range use. The port takes all the memory 492391SN/A * access types and roles them into one read() and write() call that the device 502391SN/A * must respond to. The device must also provide the addressRanges() function 512391SN/A * with which it returns the address ranges it is interested in. 528229SN/A */ 536712SN/Aclass PioPort : public SimpleTimingPort 542391SN/A{ 552391SN/A protected: 562391SN/A /** The device that this port serves. */ 576329SN/A PioDevice *device; 586658SN/A 598232SN/A virtual Tick recvAtomic(PacketPtr pkt); 608232SN/A 618931Sandreas.hansson@arm.com virtual void getDeviceAddressRanges(AddrRangeList &resp, 623879SN/A bool &snoop); 639053Sdam.sunwoo@arm.com 642394SN/A public: 652391SN/A 662391SN/A PioPort(PioDevice *dev, System *s, std::string pname = "-pioport"); 678931Sandreas.hansson@arm.com}; 688931Sandreas.hansson@arm.com 699053Sdam.sunwoo@arm.com 709053Sdam.sunwoo@arm.comclass DmaPort : public Port 712391SN/A{ 727730SN/A protected: 732391SN/A struct DmaReqState : public Packet::SenderState 742391SN/A { 755477SN/A /** Event to call on the device when this transaction (all packets) 765477SN/A * complete. */ 775477SN/A Event *completionEvent; 787730SN/A 797730SN/A /** Where we came from for some sanity checking. */ 807730SN/A Port *outPort; 817730SN/A 827730SN/A /** Total number of bytes that this transaction involves. */ 837730SN/A Addr totBytes; 847730SN/A 858931Sandreas.hansson@arm.com /** Number of bytes that have been acked for this transaction. */ 868931Sandreas.hansson@arm.com Addr numBytes; 878931Sandreas.hansson@arm.com 888931Sandreas.hansson@arm.com DmaReqState(Event *ce, Port *p, Addr tb) 898931Sandreas.hansson@arm.com : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0) 908931Sandreas.hansson@arm.com {} 917730SN/A }; 928931Sandreas.hansson@arm.com 937730SN/A DmaDevice *device; 947730SN/A std::list<PacketPtr> transmitList; 952391SN/A 963012SN/A /** The system that device/port are in. This is used to select which mode 972391SN/A * we are currently operating in. */ 987730SN/A System *sys; 997730SN/A 1007730SN/A /** Number of outstanding packets the dma port has. */ 1017730SN/A int pendingCount; 1022391SN/A 1032391SN/A /** If a dmaAction is in progress. */ 1043751SN/A int actionInProgress; 1054762SN/A 1067730SN/A /** If we need to drain, keep the drain event around until we're done 1072391SN/A * here.*/ 1082391SN/A Event *drainEvent; 1092541SN/A 1108931Sandreas.hansson@arm.com /** time to wait between sending another packet, increases as NACKs are 1112391SN/A * recived, decreases as responses are recived. */ 1123012SN/A Tick backoffTime; 1137730SN/A 1142391SN/A /** If the port is currently waiting for a retry before it can send whatever 1152391SN/A * it is that it's sending. */ 1168719SN/A bool inRetry; 1178931Sandreas.hansson@arm.com 1188719SN/A virtual bool recvTiming(PacketPtr pkt); 1198719SN/A virtual Tick recvAtomic(PacketPtr pkt) 1208719SN/A { panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN } 1219053Sdam.sunwoo@arm.com virtual void recvFunctional(PacketPtr pkt) 1229053Sdam.sunwoo@arm.com { panic("dma port shouldn't be used for pio access."); } 1238719SN/A 1249053Sdam.sunwoo@arm.com virtual void recvStatusChange(Status status) 1258719SN/A { ; } 1268719SN/A 1279053Sdam.sunwoo@arm.com virtual void recvRetry() ; 1288719SN/A 1299053Sdam.sunwoo@arm.com virtual void getDeviceAddressRanges(AddrRangeList &resp, 1309053Sdam.sunwoo@arm.com bool &snoop) 1319053Sdam.sunwoo@arm.com { resp.clear(); snoop = false; } 1328719SN/A 1339053Sdam.sunwoo@arm.com void queueDma(PacketPtr pkt, bool front = false); 1348719SN/A void sendDma(); 1358719SN/A 1369053Sdam.sunwoo@arm.com /** event to give us a kick every time we backoff time is reached. */ 1378719SN/A EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent; 1389053Sdam.sunwoo@arm.com 1399053Sdam.sunwoo@arm.com public: 1409053Sdam.sunwoo@arm.com DmaPort(DmaDevice *dev, System *s); 1418719SN/A 1429053Sdam.sunwoo@arm.com void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 1438719SN/A uint8_t *data = NULL); 1448719SN/A 1459053Sdam.sunwoo@arm.com bool dmaPending() { return pendingCount > 0; } 1468719SN/A 1479053Sdam.sunwoo@arm.com int cacheBlockSize() { return peerBlockSize(); } 1489053Sdam.sunwoo@arm.com unsigned int drain(Event *de); 1499053Sdam.sunwoo@arm.com}; 1508719SN/A 1519053Sdam.sunwoo@arm.com/** 1528719SN/A * This device is the base class which all devices senstive to an address range 1538719SN/A * inherit from. There are three pure virtual functions which all devices must 1549053Sdam.sunwoo@arm.com * implement addressRanges(), read(), and write(). The magic do choose which 1558719SN/A * mode we are in, etc is handled by the PioPort so the device doesn't have to 1569053Sdam.sunwoo@arm.com * bother. 1579053Sdam.sunwoo@arm.com */ 1589053Sdam.sunwoo@arm.comclass PioDevice : public MemObject 1598719SN/A{ 1609053Sdam.sunwoo@arm.com protected: 1618719SN/A 1628719SN/A /** The platform we are in. This is used to decide what type of memory 1639053Sdam.sunwoo@arm.com * transaction we should perform. */ 1648719SN/A Platform *platform; 1659053Sdam.sunwoo@arm.com 1669053Sdam.sunwoo@arm.com System *sys; 1679053Sdam.sunwoo@arm.com 1688719SN/A /** The pioPort that handles the requests for us and provides us requests 1699053Sdam.sunwoo@arm.com * that it sees. */ 1708719SN/A PioPort *pioPort; 1718719SN/A 1729053Sdam.sunwoo@arm.com virtual void addressRanges(AddrRangeList &range_list) = 0; 1738719SN/A 1749053Sdam.sunwoo@arm.com /** Pure virtual function that the device must implement. Called 1759053Sdam.sunwoo@arm.com * when a read command is recieved by the port. 1769053Sdam.sunwoo@arm.com * @param pkt Packet describing this request 1778719SN/A * @return number of ticks it took to complete 1788719SN/A */ 1798719SN/A virtual Tick read(PacketPtr pkt) = 0; 1808719SN/A 1818719SN/A /** Pure virtual function that the device must implement. Called when a 1829053Sdam.sunwoo@arm.com * write command is recieved by the port. 1838719SN/A * @param pkt Packet describing this request 1849053Sdam.sunwoo@arm.com * @return number of ticks it took to complete 1859053Sdam.sunwoo@arm.com */ 1869053Sdam.sunwoo@arm.com virtual Tick write(PacketPtr pkt) = 0; 1879053Sdam.sunwoo@arm.com 1888719SN/A public: 1898719SN/A /** Params struct which is extended through each device based on 1908719SN/A * the parameters it needs. Since we are re-writing everything, we 1918719SN/A * might as well start from the bottom this time. */ 1928719SN/A struct Params 1939053Sdam.sunwoo@arm.com { 1948719SN/A std::string name; 1959053Sdam.sunwoo@arm.com Platform *platform; 1969053Sdam.sunwoo@arm.com System *system; 1979053Sdam.sunwoo@arm.com }; 1988719SN/A 1998719SN/A protected: 2008719SN/A Params *_params; 2018719SN/A 2028719SN/A public: 2039053Sdam.sunwoo@arm.com const Params *params() const { return _params; } 2048719SN/A 2059053Sdam.sunwoo@arm.com PioDevice(Params *p) 2069053Sdam.sunwoo@arm.com : MemObject(p->name), platform(p->platform), sys(p->system), 2079053Sdam.sunwoo@arm.com pioPort(NULL), _params(p) 2088719SN/A {} 2098719SN/A 2108719SN/A virtual ~PioDevice(); 2118719SN/A 2128719SN/A virtual void init(); 2139053Sdam.sunwoo@arm.com 2148719SN/A virtual unsigned int drain(Event *de); 2159053Sdam.sunwoo@arm.com 2169053Sdam.sunwoo@arm.com virtual Port *getPort(const std::string &if_name, int idx = -1) 2179053Sdam.sunwoo@arm.com { 2188719SN/A if (if_name == "pio") { 2198719SN/A if (pioPort != NULL) 2208719SN/A panic("pio port already connected to."); 2218719SN/A pioPort = new PioPort(this, sys); 2228719SN/A return pioPort; 2238719SN/A } else 2248931Sandreas.hansson@arm.com return NULL; 2258931Sandreas.hansson@arm.com } 2262408SN/A friend class PioPort; 2278931Sandreas.hansson@arm.com 2282408SN/A}; 2292408SN/A 2303170SN/Aclass BasicPioDevice : public PioDevice 2316076SN/A{ 2323170SN/A public: 2338931Sandreas.hansson@arm.com struct Params : public PioDevice::Params 2343170SN/A { 2354626SN/A Addr pio_addr; 2363170SN/A Tick pio_delay; 2373170SN/A }; 2383170SN/A 2393170SN/A protected: 2403170SN/A /** Address that the device listens to. */ 2413170SN/A Addr pioAddr; 2423170SN/A 2433170SN/A /** Size that the device's address range. */ 2443170SN/A Addr pioSize; 2455714SN/A 2465714SN/A /** Delay that the device experinces on an access. */ 2473170SN/A Tick pioDelay; 2483170SN/A 2493170SN/A public: 2503170SN/A BasicPioDevice(Params *p) 2513170SN/A : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), 2523170SN/A pioDelay(p->pio_delay) 2535714SN/A {} 2545714SN/A 2553170SN/A /** return the address ranges that this device responds to. 2563170SN/A * @param range_list range list to populate with ranges 2573170SN/A */ 2583170SN/A void addressRanges(AddrRangeList &range_list); 2593170SN/A 2603170SN/A}; 2613170SN/A 2623170SN/Aclass DmaDevice : public PioDevice 2633170SN/A{ 2648931Sandreas.hansson@arm.com public: 2653170SN/A struct Params : public PioDevice::Params 2664626SN/A { 2673170SN/A Tick min_backoff_delay; 2686102SN/A Tick max_backoff_delay; 2693170SN/A }; 2703170SN/A 2713170SN/A protected: 2723170SN/A DmaPort *dmaPort; 2736102SN/A Tick minBackoffDelay; 2743170SN/A Tick maxBackoffDelay; 2753170SN/A 2763170SN/A public: 2773170SN/A DmaDevice(Params *p); 2783170SN/A virtual ~DmaDevice(); 2793170SN/A 2803170SN/A void dmaWrite(Addr addr, int size, Event *event, uint8_t *data) 2813170SN/A { 2823170SN/A dmaPort->dmaAction(MemCmd::WriteInvalidateReq, 2833170SN/A addr, size, event, data); 2843170SN/A } 2856102SN/A 2863170SN/A void dmaRead(Addr addr, int size, Event *event, uint8_t *data) 2873170SN/A { 2883170SN/A dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data); 2895714SN/A } 2905714SN/A 2913170SN/A bool dmaPending() { return dmaPort->dmaPending(); } 2923170SN/A 2933170SN/A virtual unsigned int drain(Event *de); 2943170SN/A 2955714SN/A int cacheBlockSize() { return dmaPort->cacheBlockSize(); } 2965714SN/A 2973170SN/A virtual Port *getPort(const std::string &if_name, int idx = -1) 2983170SN/A { 2993170SN/A if (if_name == "pio") { 3003170SN/A if (pioPort != NULL) 3013170SN/A panic("pio port already connected to."); 3023170SN/A pioPort = new PioPort(this, sys); 3033170SN/A return pioPort; 3043170SN/A } else if (if_name == "dma") { 3056102SN/A if (dmaPort != NULL) 3064040SN/A panic("dma port already connected to."); 3073170SN/A dmaPort = new DmaPort(this, sys); 3083170SN/A return dmaPort; 3093170SN/A } else 3103170SN/A return NULL; 3113170SN/A } 3124626SN/A 3134626SN/A friend class DmaPort; 3144626SN/A}; 3154626SN/A 3164626SN/A 3176429SN/A#endif // __DEV_IO_DEVICE_HH__ 3186429SN/A