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