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