io_device.hh revision 5534
12SN/A/*
21762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
292665Ssaidi@eecs.umich.edu *          Nathan Binkert
302SN/A */
312SN/A
321388SN/A#ifndef __DEV_IO_DEVICE_HH__
332SN/A#define __DEV_IO_DEVICE_HH__
342SN/A
352SN/A#include "base/fast_alloc.hh"
361191SN/A#include "mem/mem_object.hh"
371191SN/A#include "mem/packet.hh"
381191SN/A#include "mem/tport.hh"
391388SN/A#include "params/BasicPioDevice.hh"
401717SN/A#include "params/DmaDevice.hh"
412651Ssaidi@eecs.umich.edu#include "params/PioDevice.hh"
422680Sktlim@umich.edu#include "sim/sim_object.hh"
431977SN/A
443144Shsul@eecs.umich.educlass Event;
45161SN/Aclass Platform;
462190SN/Aclass PioDevice;
4756SN/Aclass DmaDevice;
482190SN/Aclass System;
492SN/A
501062SN/A/**
511062SN/A * The PioPort class is a programmed i/o port that all devices that are
522359SN/A * sensitive to an address range use. The port takes all the memory
532359SN/A * access types and roles them into one read() and write() call that the device
542359SN/A * must respond to. The device must also provide the addressRanges() function
552SN/A * with which it returns the address ranges it is interested in.
562SN/A */
572SN/Aclass PioPort : public SimpleTimingPort
582SN/A{
592SN/A  protected:
602SN/A    /** The device that this port serves. */
612SN/A    PioDevice *device;
622SN/A
632SN/A    virtual Tick recvAtomic(PacketPtr pkt);
643126Sktlim@umich.edu
653126Sktlim@umich.edu    virtual void getDeviceAddressRanges(AddrRangeList &resp,
664075Sbinkertn@umich.edu                                        bool &snoop);
673126Sktlim@umich.edu
683126Sktlim@umich.edu  public:
693126Sktlim@umich.edu
703126Sktlim@umich.edu    PioPort(PioDevice *dev, System *s, std::string pname = "-pioport");
713126Sktlim@umich.edu};
723126Sktlim@umich.edu
732356SN/A
742356SN/Aclass DmaPort : public Port
752356SN/A{
762367SN/A  protected:
772356SN/A    struct DmaReqState : public Packet::SenderState, public FastAlloc
782356SN/A    {
792367SN/A        /** Event to call on the device when this transaction (all packets)
802356SN/A         * complete. */
812356SN/A        Event *completionEvent;
822356SN/A
832367SN/A        /** Where we came from for some sanity checking. */
842367SN/A        Port *outPort;
852367SN/A
862367SN/A        /** Total number of bytes that this transaction involves. */
872356SN/A        Addr totBytes;
882356SN/A
892356SN/A        /** Number of bytes that have been acked for this transaction. */
902356SN/A        Addr numBytes;
912356SN/A
922356SN/A        /** Amount to delay completion of dma by */
932356SN/A        Tick delay;
942356SN/A
952356SN/A        DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay)
962356SN/A            : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0),
971858SN/A              delay(_delay)
981400SN/A        {}
993923Shsul@eecs.umich.edu    };
1003661Srdreslin@umich.edu
1013661Srdreslin@umich.edu    DmaDevice *device;
1022SN/A    std::list<PacketPtr> transmitList;
1031400SN/A
1042856Srdreslin@umich.edu    /** The system that device/port are in. This is used to select which mode
1053661Srdreslin@umich.edu     * we are currently operating in. */
1063661Srdreslin@umich.edu    System *sys;
1072SN/A
1082SN/A    /** Number of outstanding packets the dma port has. */
1092359SN/A    int pendingCount;
1102831Sksewell@umich.edu
1111062SN/A    /** If a dmaAction is in progress. */
1122SN/A    int actionInProgress;
1132SN/A
1142SN/A    /** If we need to drain, keep the drain event around until we're done
1152831Sksewell@umich.edu     * here.*/
1161062SN/A    Event *drainEvent;
1171062SN/A
1182SN/A    /** time to wait between sending another packet, increases as NACKs are
1192SN/A     * recived, decreases as responses are recived. */
1202SN/A    Tick backoffTime;
1212SN/A
1221354SN/A    /** If the port is currently waiting for a retry before it can send whatever
1232SN/A     * it is that it's sending. */
124503SN/A    bool inRetry;
1252SN/A
1262SN/A    virtual bool recvTiming(PacketPtr pkt);
1272SN/A    virtual Tick recvAtomic(PacketPtr pkt)
1282SN/A    { panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN }
1291400SN/A    virtual void recvFunctional(PacketPtr pkt)
1302SN/A    { panic("dma port shouldn't be used for pio access."); }
1313144Shsul@eecs.umich.edu
1323144Shsul@eecs.umich.edu    virtual void recvStatusChange(Status status)
1333144Shsul@eecs.umich.edu    { ; }
1342SN/A
1351400SN/A    virtual void recvRetry() ;
1362SN/A
1372SN/A    virtual void getDeviceAddressRanges(AddrRangeList &resp,
1382SN/A                                        bool &snoop)
1392SN/A    { resp.clear(); snoop = false; }
1402SN/A
1412SN/A    void queueDma(PacketPtr pkt, bool front = false);
142503SN/A    void sendDma();
1432SN/A
1441400SN/A    /** event to give us a kick every time we backoff time is reached. */
1452SN/A    EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent;
1462SN/A
147124SN/A  public:
1481354SN/A    DmaPort(DmaDevice *dev, System *s);
149124SN/A
150124SN/A    void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
151124SN/A                   uint8_t *data, Tick delay);
152124SN/A
153124SN/A    bool dmaPending() { return pendingCount > 0; }
154124SN/A
1551400SN/A    int cacheBlockSize() { return peerBlockSize(); }
156124SN/A    unsigned int drain(Event *de);
1573144Shsul@eecs.umich.edu};
1583144Shsul@eecs.umich.edu
1593144Shsul@eecs.umich.edu/**
160124SN/A * This device is the base class which all devices senstive to an address range
1611400SN/A * inherit from. There are three pure virtual functions which all devices must
162124SN/A * implement addressRanges(), read(), and write(). The magic do choose which
163124SN/A * mode we are in, etc is handled by the PioPort so the device doesn't have to
164124SN/A * bother.
165124SN/A */
166124SN/Aclass PioDevice : public MemObject
167124SN/A{
168124SN/A  protected:
169124SN/A
1701400SN/A    /** The platform we are in. This is used to decide what type of memory
171124SN/A     * transaction we should perform. */
172124SN/A    Platform *platform;
1731191SN/A
1741400SN/A    System *sys;
1751388SN/A
1761191SN/A    /** The pioPort that handles the requests for us and provides us requests
1771400SN/A     * that it sees. */
1781191SN/A    PioPort *pioPort;
1791400SN/A
1801191SN/A    virtual void addressRanges(AddrRangeList &range_list) = 0;
1811191SN/A
1824471Sstever@eecs.umich.edu    /** Pure virtual function that the device must implement. Called
1834471Sstever@eecs.umich.edu     * when a read command is recieved by the port.
1844471Sstever@eecs.umich.edu     * @param pkt Packet describing this request
1851191SN/A     * @return number of ticks it took to complete
1861191SN/A     */
1871917SN/A    virtual Tick read(PacketPtr pkt) = 0;
1881917SN/A
1891917SN/A    /** Pure virtual function that the device must implement. Called when a
1901917SN/A     * write command is recieved by the port.
1911917SN/A     * @param pkt Packet describing this request
1922SN/A     * @return number of ticks it took to complete
1932SN/A     */
1941917SN/A    virtual Tick write(PacketPtr pkt) = 0;
1951917SN/A
1961917SN/A  public:
1971917SN/A    typedef PioDeviceParams Params;
1981917SN/A    PioDevice(const Params *p);
1992315SN/A    virtual ~PioDevice();
2001917SN/A
2011191SN/A    const Params *
2021191SN/A    params() const
2031191SN/A    {
2041191SN/A        return dynamic_cast<const Params *>(_params);
2051191SN/A    }
2061191SN/A
2071191SN/A    virtual void init();
2081191SN/A
2091191SN/A    virtual unsigned int drain(Event *de);
2101191SN/A
2111191SN/A    virtual Port *getPort(const std::string &if_name, int idx = -1)
2121129SN/A    {
2131129SN/A        if (if_name == "pio") {
2141129SN/A            if (pioPort != NULL)
2151400SN/A                panic("pio port already connected to.");
2162680Sktlim@umich.edu            pioPort = new PioPort(this, sys);
2171129SN/A            return pioPort;
218180SN/A        } else
2192SN/A            return NULL;
2201917SN/A    }
2211917SN/A    friend class PioPort;
2221917SN/A
2231917SN/A};
2241917SN/A
2251917SN/Aclass BasicPioDevice : public PioDevice
2262356SN/A{
2272356SN/A  protected:
2284031Sktlim@umich.edu    /** Address that the device listens to. */
2294031Sktlim@umich.edu    Addr pioAddr;
2302356SN/A
2312356SN/A    /** Size that the device's address range. */
2321917SN/A    Addr pioSize;
2331917SN/A
2341917SN/A    /** Delay that the device experinces on an access. */
2351917SN/A    Tick pioDelay;
2362SN/A
2372SN/A  public:
238729SN/A    typedef BasicPioDeviceParams Params;
239707SN/A    BasicPioDevice(const Params *p);
240707SN/A
241707SN/A    const Params *
242707SN/A    params() const
243707SN/A    {
244707SN/A        return dynamic_cast<const Params *>(_params);
2452680Sktlim@umich.edu    }
2462SN/A
2472SN/A    /** return the address ranges that this device responds to.
2482SN/A     * @param range_list range list to populate with ranges
2492SN/A     */
2502680Sktlim@umich.edu    void addressRanges(AddrRangeList &range_list);
2512SN/A
2522SN/A};
2532680Sktlim@umich.edu
2542190SN/Aclass DmaDevice : public PioDevice
2552190SN/A{
2562190SN/A   protected:
2572SN/A    DmaPort *dmaPort;
2582SN/A    Tick minBackoffDelay;
2593495Sktlim@umich.edu    Tick maxBackoffDelay;
2603495Sktlim@umich.edu
2613495Sktlim@umich.edu  public:
2623661Srdreslin@umich.edu    typedef DmaDeviceParams Params;
2633495Sktlim@umich.edu    DmaDevice(const Params *p);
2643661Srdreslin@umich.edu    virtual ~DmaDevice();
2653495Sktlim@umich.edu
2663495Sktlim@umich.edu    const Params *
2673495Sktlim@umich.edu    params() const
2683495Sktlim@umich.edu    {
2693495Sktlim@umich.edu        return dynamic_cast<const Params *>(_params);
2703495Sktlim@umich.edu    }
2713495Sktlim@umich.edu
2723661Srdreslin@umich.edu    void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0)
2733661Srdreslin@umich.edu    {
2743495Sktlim@umich.edu        dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data, delay);
2753495Sktlim@umich.edu    }
2763495Sktlim@umich.edu
2773495Sktlim@umich.edu    void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0)
2783495Sktlim@umich.edu    {
2793495Sktlim@umich.edu        dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data, delay);
2803495Sktlim@umich.edu    }
281180SN/A
282180SN/A    bool dmaPending() { return dmaPort->dmaPending(); }
2832680Sktlim@umich.edu
284180SN/A    virtual unsigned int drain(Event *de);
2852680Sktlim@umich.edu
2862680Sktlim@umich.edu    int cacheBlockSize() { return dmaPort->cacheBlockSize(); }
2872378SN/A
2881858SN/A    virtual Port *getPort(const std::string &if_name, int idx = -1)
2891806SN/A    {
2901806SN/A        if (if_name == "pio") {
2911806SN/A            if (pioPort != NULL)
292180SN/A                panic("pio port already connected to.");
2932680Sktlim@umich.edu            pioPort = new PioPort(this, sys);
294180SN/A            return pioPort;
2952680Sktlim@umich.edu        } else if (if_name == "dma") {
296180SN/A            if (dmaPort != NULL)
297180SN/A                panic("dma port already connected to.");
298180SN/A            dmaPort = new DmaPort(this, sys);
299180SN/A            return dmaPort;
300180SN/A        } else
3014000Ssaidi@eecs.umich.edu            return NULL;
3024000Ssaidi@eecs.umich.edu    }
3034000Ssaidi@eecs.umich.edu
3044000Ssaidi@eecs.umich.edu    friend class DmaPort;
3054000Ssaidi@eecs.umich.edu};
3064000Ssaidi@eecs.umich.edu
3074000Ssaidi@eecs.umich.edu
3084000Ssaidi@eecs.umich.edu#endif // __DEV_IO_DEVICE_HH__
3094000Ssaidi@eecs.umich.edu