dma_device.hh revision 8832
12735Sktlim@umich.edu/*
210319SAndreas.Sandberg@ARM.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
310319SAndreas.Sandberg@ARM.com * All rights reserved.
410319SAndreas.Sandberg@ARM.com *
510319SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
610319SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
710319SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
810319SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
910319SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
1010319SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
1110319SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
1210319SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
1310319SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
142735Sktlim@umich.edu * this software without specific prior written permission.
1511303Ssteve.reinhardt@amd.com *
162735Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172735Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182735Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192735Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202735Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212735Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222735Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232735Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242735Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252735Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262735Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272735Sktlim@umich.edu *
282735Sktlim@umich.edu * Authors: Ali Saidi
292735Sktlim@umich.edu *          Nathan Binkert
302735Sktlim@umich.edu */
312735Sktlim@umich.edu
322735Sktlim@umich.edu#ifndef __DEV_IO_DEVICE_HH__
332735Sktlim@umich.edu#define __DEV_IO_DEVICE_HH__
342735Sktlim@umich.edu
352735Sktlim@umich.edu#include "base/fast_alloc.hh"
362735Sktlim@umich.edu#include "mem/mem_object.hh"
372735Sktlim@umich.edu#include "mem/packet.hh"
382735Sktlim@umich.edu#include "mem/tport.hh"
392735Sktlim@umich.edu#include "params/BasicPioDevice.hh"
402735Sktlim@umich.edu#include "params/DmaDevice.hh"
412735Sktlim@umich.edu#include "params/PioDevice.hh"
4210319SAndreas.Sandberg@ARM.com#include "sim/sim_object.hh"
432735Sktlim@umich.edu
442735Sktlim@umich.educlass Event;
4510319SAndreas.Sandberg@ARM.comclass PioDevice;
4610319SAndreas.Sandberg@ARM.comclass DmaDevice;
4710319SAndreas.Sandberg@ARM.comclass System;
4810319SAndreas.Sandberg@ARM.com
4910319SAndreas.Sandberg@ARM.com/**
5010319SAndreas.Sandberg@ARM.com * The PioPort class is a programmed i/o port that all devices that are
5110529Smorr@cs.wisc.edu * sensitive to an address range use. The port takes all the memory
5212104Snathanael.premillieu@arm.com * access types and roles them into one read() and write() call that the device
5310319SAndreas.Sandberg@ARM.com * must respond to. The device must also provide getAddrRanges() function
5410319SAndreas.Sandberg@ARM.com * with which it returns the address ranges it is interested in.
5511608Snikos.nikoleris@arm.com */
562735Sktlim@umich.educlass PioPort : public SimpleTimingPort
572735Sktlim@umich.edu{
5810319SAndreas.Sandberg@ARM.com  protected:
5910319SAndreas.Sandberg@ARM.com    /** The device that this port serves. */
6010319SAndreas.Sandberg@ARM.com    PioDevice *device;
6110319SAndreas.Sandberg@ARM.com
6210319SAndreas.Sandberg@ARM.com    virtual Tick recvAtomic(PacketPtr pkt);
6310319SAndreas.Sandberg@ARM.com
6410319SAndreas.Sandberg@ARM.com    virtual AddrRangeList getAddrRanges();
6510319SAndreas.Sandberg@ARM.com
6610319SAndreas.Sandberg@ARM.com  public:
6710319SAndreas.Sandberg@ARM.com
6810319SAndreas.Sandberg@ARM.com    PioPort(PioDevice *dev, System *s, std::string pname = "-pioport");
6910319SAndreas.Sandberg@ARM.com};
7010319SAndreas.Sandberg@ARM.com
7110319SAndreas.Sandberg@ARM.com
722735Sktlim@umich.educlass DmaPort : public Port
732735Sktlim@umich.edu{
7410319SAndreas.Sandberg@ARM.com  protected:
7510319SAndreas.Sandberg@ARM.com    struct DmaReqState : public Packet::SenderState, public FastAlloc
7610319SAndreas.Sandberg@ARM.com    {
7710319SAndreas.Sandberg@ARM.com        /** Event to call on the device when this transaction (all packets)
7810319SAndreas.Sandberg@ARM.com         * complete. */
7910319SAndreas.Sandberg@ARM.com        Event *completionEvent;
8010319SAndreas.Sandberg@ARM.com
8110319SAndreas.Sandberg@ARM.com        /** Where we came from for some sanity checking. */
8210319SAndreas.Sandberg@ARM.com        Port *outPort;
8310319SAndreas.Sandberg@ARM.com
8410319SAndreas.Sandberg@ARM.com        /** Total number of bytes that this transaction involves. */
8510319SAndreas.Sandberg@ARM.com        Addr totBytes;
8610319SAndreas.Sandberg@ARM.com
8710319SAndreas.Sandberg@ARM.com        /** Number of bytes that have been acked for this transaction. */
8810319SAndreas.Sandberg@ARM.com        Addr numBytes;
892735Sktlim@umich.edu
902735Sktlim@umich.edu        /** Amount to delay completion of dma by */
9110319SAndreas.Sandberg@ARM.com        Tick delay;
9210319SAndreas.Sandberg@ARM.com
9310319SAndreas.Sandberg@ARM.com
9410319SAndreas.Sandberg@ARM.com        DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay)
9510319SAndreas.Sandberg@ARM.com            : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0),
9610319SAndreas.Sandberg@ARM.com              delay(_delay)
9710319SAndreas.Sandberg@ARM.com        {}
9810319SAndreas.Sandberg@ARM.com    };
9910319SAndreas.Sandberg@ARM.com
10010319SAndreas.Sandberg@ARM.com    MemObject *device;
10110319SAndreas.Sandberg@ARM.com    std::list<PacketPtr> transmitList;
10210319SAndreas.Sandberg@ARM.com
10310319SAndreas.Sandberg@ARM.com    /** The system that device/port are in. This is used to select which mode
1042735Sktlim@umich.edu     * we are currently operating in. */
1052735Sktlim@umich.edu    System *sys;
10610319SAndreas.Sandberg@ARM.com
1072735Sktlim@umich.edu    /** Id for all requests */
1082735Sktlim@umich.edu    MasterID masterId;
1092735Sktlim@umich.edu
11010319SAndreas.Sandberg@ARM.com    /** Number of outstanding packets the dma port has. */
11110319SAndreas.Sandberg@ARM.com    int pendingCount;
1122735Sktlim@umich.edu
1132735Sktlim@umich.edu    /** If a dmaAction is in progress. */
11410319SAndreas.Sandberg@ARM.com    int actionInProgress;
11510319SAndreas.Sandberg@ARM.com
1162735Sktlim@umich.edu    /** If we need to drain, keep the drain event around until we're done
1172735Sktlim@umich.edu     * here.*/
1182735Sktlim@umich.edu    Event *drainEvent;
11910319SAndreas.Sandberg@ARM.com
12010319SAndreas.Sandberg@ARM.com    /** time to wait between sending another packet, increases as NACKs are
1212735Sktlim@umich.edu     * recived, decreases as responses are recived. */
12210319SAndreas.Sandberg@ARM.com    Tick backoffTime;
1232735Sktlim@umich.edu
12410319SAndreas.Sandberg@ARM.com    /** Minimum time that device should back off for after failed sendTiming */
12510319SAndreas.Sandberg@ARM.com    Tick minBackoffDelay;
12610319SAndreas.Sandberg@ARM.com
12710319SAndreas.Sandberg@ARM.com    /** Maximum time that device should back off for after failed sendTiming */
12810319SAndreas.Sandberg@ARM.com    Tick maxBackoffDelay;
12910319SAndreas.Sandberg@ARM.com
13010319SAndreas.Sandberg@ARM.com    /** If the port is currently waiting for a retry before it can send whatever
1312735Sktlim@umich.edu     * it is that it's sending. */
13210319SAndreas.Sandberg@ARM.com    bool inRetry;
13310319SAndreas.Sandberg@ARM.com
13410319SAndreas.Sandberg@ARM.com    /** Port accesses a cache which requires snooping */
13510319SAndreas.Sandberg@ARM.com    bool recvSnoops;
13610319SAndreas.Sandberg@ARM.com
13710319SAndreas.Sandberg@ARM.com    virtual bool recvTiming(PacketPtr pkt);
13810319SAndreas.Sandberg@ARM.com    virtual Tick recvAtomic(PacketPtr pkt)
1392735Sktlim@umich.edu    {
14010319SAndreas.Sandberg@ARM.com        if (recvSnoops) return 0;
14110319SAndreas.Sandberg@ARM.com
14210319SAndreas.Sandberg@ARM.com        panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN
14310319SAndreas.Sandberg@ARM.com    }
14410319SAndreas.Sandberg@ARM.com    virtual void recvFunctional(PacketPtr pkt)
1452735Sktlim@umich.edu    {
14610319SAndreas.Sandberg@ARM.com        if (recvSnoops) return;
14710319SAndreas.Sandberg@ARM.com
14810319SAndreas.Sandberg@ARM.com        panic("dma port shouldn't be used for pio access.");
14910319SAndreas.Sandberg@ARM.com    }
15010319SAndreas.Sandberg@ARM.com
1512735Sktlim@umich.edu    virtual void recvRangeChange()
15210319SAndreas.Sandberg@ARM.com    {
1532735Sktlim@umich.edu        // DMA port is a master with a single slave so there is no choice and
15410319SAndreas.Sandberg@ARM.com        // thus no need to worry about any address changes
15510319SAndreas.Sandberg@ARM.com    }
15610319SAndreas.Sandberg@ARM.com
15710319SAndreas.Sandberg@ARM.com    virtual void recvRetry() ;
15810319SAndreas.Sandberg@ARM.com
15910319SAndreas.Sandberg@ARM.com    virtual bool isSnooping()
16010319SAndreas.Sandberg@ARM.com    { return recvSnoops; }
16110319SAndreas.Sandberg@ARM.com
16210319SAndreas.Sandberg@ARM.com    void queueDma(PacketPtr pkt, bool front = false);
16310319SAndreas.Sandberg@ARM.com    void sendDma();
16410319SAndreas.Sandberg@ARM.com
16510319SAndreas.Sandberg@ARM.com    /** event to give us a kick every time we backoff time is reached. */
16610319SAndreas.Sandberg@ARM.com    EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent;
16710319SAndreas.Sandberg@ARM.com
16810319SAndreas.Sandberg@ARM.com  public:
16910319SAndreas.Sandberg@ARM.com    DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff,
17010319SAndreas.Sandberg@ARM.com            bool recv_snoops = false);
17110319SAndreas.Sandberg@ARM.com
17210319SAndreas.Sandberg@ARM.com    void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
17310319SAndreas.Sandberg@ARM.com                   uint8_t *data, Tick delay, Request::Flags flag = 0);
17410319SAndreas.Sandberg@ARM.com
17510319SAndreas.Sandberg@ARM.com    bool dmaPending() { return pendingCount > 0; }
17610319SAndreas.Sandberg@ARM.com
17710319SAndreas.Sandberg@ARM.com    unsigned cacheBlockSize() const { return peerBlockSize(); }
17810319SAndreas.Sandberg@ARM.com    unsigned int drain(Event *de);
17911303Ssteve.reinhardt@amd.com};
18011303Ssteve.reinhardt@amd.com
18111303Ssteve.reinhardt@amd.com/**
18211303Ssteve.reinhardt@amd.com * This device is the base class which all devices senstive to an address range
18311303Ssteve.reinhardt@amd.com * inherit from. There are three pure virtual functions which all devices must
18411303Ssteve.reinhardt@amd.com * implement getAddrRanges(), read(), and write(). The magic do choose which
18511303Ssteve.reinhardt@amd.com * mode we are in, etc is handled by the PioPort so the device doesn't have to
18610319SAndreas.Sandberg@ARM.com * bother.
18711608Snikos.nikoleris@arm.com */
18811303Ssteve.reinhardt@amd.comclass PioDevice : public MemObject
18911303Ssteve.reinhardt@amd.com{
19011303Ssteve.reinhardt@amd.com  protected:
19110319SAndreas.Sandberg@ARM.com    System *sys;
19211303Ssteve.reinhardt@amd.com
19311303Ssteve.reinhardt@amd.com    /** The pioPort that handles the requests for us and provides us requests
19411303Ssteve.reinhardt@amd.com     * that it sees. */
19511303Ssteve.reinhardt@amd.com    PioPort *pioPort;
19611303Ssteve.reinhardt@amd.com
19711303Ssteve.reinhardt@amd.com    /**
19811303Ssteve.reinhardt@amd.com     * Every PIO device is obliged to provide an implementation that
19911303Ssteve.reinhardt@amd.com     * returns the address ranges the device responds to.
20011608Snikos.nikoleris@arm.com     *
20111303Ssteve.reinhardt@amd.com     * @return a list of non-overlapping address ranges
20211303Ssteve.reinhardt@amd.com     */
20311303Ssteve.reinhardt@amd.com    virtual AddrRangeList getAddrRanges() = 0;
20411303Ssteve.reinhardt@amd.com
20511303Ssteve.reinhardt@amd.com    /** Pure virtual function that the device must implement. Called
20611303Ssteve.reinhardt@amd.com     * when a read command is recieved by the port.
20711303Ssteve.reinhardt@amd.com     * @param pkt Packet describing this request
20811303Ssteve.reinhardt@amd.com     * @return number of ticks it took to complete
20910319SAndreas.Sandberg@ARM.com     */
21011608Snikos.nikoleris@arm.com    virtual Tick read(PacketPtr pkt) = 0;
21110319SAndreas.Sandberg@ARM.com
21210319SAndreas.Sandberg@ARM.com    /** Pure virtual function that the device must implement. Called when a
21310319SAndreas.Sandberg@ARM.com     * write command is recieved by the port.
21410319SAndreas.Sandberg@ARM.com     * @param pkt Packet describing this request
21510319SAndreas.Sandberg@ARM.com     * @return number of ticks it took to complete
21610319SAndreas.Sandberg@ARM.com     */
21710319SAndreas.Sandberg@ARM.com    virtual Tick write(PacketPtr pkt) = 0;
21810319SAndreas.Sandberg@ARM.com
21910319SAndreas.Sandberg@ARM.com  public:
22010319SAndreas.Sandberg@ARM.com    typedef PioDeviceParams Params;
22110319SAndreas.Sandberg@ARM.com    PioDevice(const Params *p);
22210319SAndreas.Sandberg@ARM.com    virtual ~PioDevice();
22310319SAndreas.Sandberg@ARM.com
22410319SAndreas.Sandberg@ARM.com    const Params *
22510319SAndreas.Sandberg@ARM.com    params() const
22610319SAndreas.Sandberg@ARM.com    {
22710319SAndreas.Sandberg@ARM.com        return dynamic_cast<const Params *>(_params);
22810319SAndreas.Sandberg@ARM.com    }
22910319SAndreas.Sandberg@ARM.com
23010319SAndreas.Sandberg@ARM.com    virtual void init();
23110319SAndreas.Sandberg@ARM.com
23211877Sbrandon.potter@amd.com    virtual unsigned int drain(Event *de);
23310319SAndreas.Sandberg@ARM.com
23410319SAndreas.Sandberg@ARM.com    virtual Port *getPort(const std::string &if_name, int idx = -1);
2352735Sktlim@umich.edu
2362735Sktlim@umich.edu    friend class PioPort;
23710319SAndreas.Sandberg@ARM.com
2382735Sktlim@umich.edu};
23910319SAndreas.Sandberg@ARM.com
24010319SAndreas.Sandberg@ARM.comclass BasicPioDevice : public PioDevice
24110319SAndreas.Sandberg@ARM.com{
24210319SAndreas.Sandberg@ARM.com  protected:
2437520Sgblack@eecs.umich.edu    /** Address that the device listens to. */
24410319SAndreas.Sandberg@ARM.com    Addr pioAddr;
24510319SAndreas.Sandberg@ARM.com
24610319SAndreas.Sandberg@ARM.com    /** Size that the device's address range. */
24710319SAndreas.Sandberg@ARM.com    Addr pioSize;
24810319SAndreas.Sandberg@ARM.com
2495702Ssaidi@eecs.umich.edu    /** Delay that the device experinces on an access. */
2505702Ssaidi@eecs.umich.edu    Tick pioDelay;
2515702Ssaidi@eecs.umich.edu
2525702Ssaidi@eecs.umich.edu  public:
2535702Ssaidi@eecs.umich.edu    typedef BasicPioDeviceParams Params;
25410319SAndreas.Sandberg@ARM.com    BasicPioDevice(const Params *p);
2558779Sgblack@eecs.umich.edu
25610319SAndreas.Sandberg@ARM.com    const Params *
2576973Stjones1@inf.ed.ac.uk    params() const
25810319SAndreas.Sandberg@ARM.com    {
25910319SAndreas.Sandberg@ARM.com        return dynamic_cast<const Params *>(_params);
26010319SAndreas.Sandberg@ARM.com    }
26110319SAndreas.Sandberg@ARM.com
26210319SAndreas.Sandberg@ARM.com    /**
26310319SAndreas.Sandberg@ARM.com     * Determine the address ranges that this device responds to.
26410319SAndreas.Sandberg@ARM.com     *
26510319SAndreas.Sandberg@ARM.com     * @return a list of non-overlapping address ranges
26610319SAndreas.Sandberg@ARM.com     */
26710319SAndreas.Sandberg@ARM.com    virtual AddrRangeList getAddrRanges();
26810319SAndreas.Sandberg@ARM.com
26910319SAndreas.Sandberg@ARM.com};
27010319SAndreas.Sandberg@ARM.com
27110319SAndreas.Sandberg@ARM.comclass DmaDevice : public PioDevice
27210319SAndreas.Sandberg@ARM.com{
27310319SAndreas.Sandberg@ARM.com   protected:
27410319SAndreas.Sandberg@ARM.com    DmaPort *dmaPort;
27510319SAndreas.Sandberg@ARM.com
27610319SAndreas.Sandberg@ARM.com  public:
27710529Smorr@cs.wisc.edu    typedef DmaDeviceParams Params;
27810529Smorr@cs.wisc.edu    DmaDevice(const Params *p);
27910529Smorr@cs.wisc.edu    virtual ~DmaDevice();
28010529Smorr@cs.wisc.edu
28110319SAndreas.Sandberg@ARM.com    const Params *
28210319SAndreas.Sandberg@ARM.com    params() const
28310319SAndreas.Sandberg@ARM.com    {
28410319SAndreas.Sandberg@ARM.com        return dynamic_cast<const Params *>(_params);
28510319SAndreas.Sandberg@ARM.com    }
28610319SAndreas.Sandberg@ARM.com
28710319SAndreas.Sandberg@ARM.com    void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0)
28810319SAndreas.Sandberg@ARM.com    {
28910319SAndreas.Sandberg@ARM.com        dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data, delay);
29012106SRekai.GonzalezAlberquilla@arm.com    }
29110319SAndreas.Sandberg@ARM.com
29212106SRekai.GonzalezAlberquilla@arm.com    void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0)
29310319SAndreas.Sandberg@ARM.com    {
29410319SAndreas.Sandberg@ARM.com        dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data, delay);
29510319SAndreas.Sandberg@ARM.com    }
29610319SAndreas.Sandberg@ARM.com
2972735Sktlim@umich.edu    bool dmaPending() { return dmaPort->dmaPending(); }
29810319SAndreas.Sandberg@ARM.com
29910319SAndreas.Sandberg@ARM.com    virtual unsigned int drain(Event *de);
300
301    unsigned cacheBlockSize() const { return dmaPort->cacheBlockSize(); }
302
303    virtual Port *getPort(const std::string &if_name, int idx = -1);
304
305    friend class DmaPort;
306};
307
308
309#endif // __DEV_IO_DEVICE_HH__
310