dma_device.hh revision 8975
1/*
2 * Copyright (c) 2012 ARM Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ali Saidi
41 *          Nathan Binkert
42 */
43
44#ifndef __DEV_IO_DEVICE_HH__
45#define __DEV_IO_DEVICE_HH__
46
47#include "base/fast_alloc.hh"
48#include "mem/mem_object.hh"
49#include "mem/packet.hh"
50#include "mem/tport.hh"
51#include "params/BasicPioDevice.hh"
52#include "params/DmaDevice.hh"
53#include "params/PioDevice.hh"
54#include "sim/sim_object.hh"
55
56class Event;
57class PioDevice;
58class DmaDevice;
59class System;
60
61/**
62 * The PioPort class is a programmed i/o port that all devices that are
63 * sensitive to an address range use. The port takes all the memory
64 * access types and roles them into one read() and write() call that the device
65 * must respond to. The device must also provide getAddrRanges() function
66 * with which it returns the address ranges it is interested in.
67 */
68class PioPort : public SimpleTimingPort
69{
70  protected:
71    /** The device that this port serves. */
72    PioDevice *device;
73
74    virtual Tick recvAtomic(PacketPtr pkt);
75
76    virtual AddrRangeList getAddrRanges();
77
78  public:
79
80    PioPort(PioDevice *dev);
81};
82
83
84class DmaPort : public MasterPort
85{
86  protected:
87    struct DmaReqState : public Packet::SenderState, public FastAlloc
88    {
89        /** Event to call on the device when this transaction (all packets)
90         * complete. */
91        Event *completionEvent;
92
93        /** Where we came from for some sanity checking. */
94        Port *outPort;
95
96        /** Total number of bytes that this transaction involves. */
97        Addr totBytes;
98
99        /** Number of bytes that have been acked for this transaction. */
100        Addr numBytes;
101
102        /** Amount to delay completion of dma by */
103        Tick delay;
104
105
106        DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay)
107            : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0),
108              delay(_delay)
109        {}
110    };
111
112    MemObject *device;
113    std::list<PacketPtr> transmitList;
114
115    /** The system that device/port are in. This is used to select which mode
116     * we are currently operating in. */
117    System *sys;
118
119    /** Id for all requests */
120    MasterID masterId;
121
122    /** Number of outstanding packets the dma port has. */
123    int pendingCount;
124
125    /** If a dmaAction is in progress. */
126    int actionInProgress;
127
128    /** If we need to drain, keep the drain event around until we're done
129     * here.*/
130    Event *drainEvent;
131
132    /** time to wait between sending another packet, increases as NACKs are
133     * recived, decreases as responses are recived. */
134    Tick backoffTime;
135
136    /** Minimum time that device should back off for after failed sendTiming */
137    Tick minBackoffDelay;
138
139    /** Maximum time that device should back off for after failed sendTiming */
140    Tick maxBackoffDelay;
141
142    /** If the port is currently waiting for a retry before it can send whatever
143     * it is that it's sending. */
144    bool inRetry;
145
146    /** Port accesses a cache which requires snooping */
147    bool recvSnoops;
148
149    virtual bool recvTimingResp(PacketPtr pkt);
150
151    virtual void recvTimingSnoopReq(PacketPtr pkt)
152    {
153        if (!recvSnoops)
154            panic("%s was not expecting a snoop\n", name());
155    }
156
157    virtual Tick recvAtomicSnoop(PacketPtr pkt)
158    {
159        if (!recvSnoops)
160            panic("%s was not expecting a snoop\n", name());
161        return 0;
162    }
163
164    virtual void recvFunctionalSnoop(PacketPtr pkt)
165    {
166        if (!recvSnoops)
167            panic("%s was not expecting a snoop\n", name());
168    }
169
170    virtual void recvRetry() ;
171
172    virtual bool isSnooping() const { return recvSnoops; }
173
174    void queueDma(PacketPtr pkt, bool front = false);
175    void sendDma();
176
177    /** event to give us a kick every time we backoff time is reached. */
178    EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent;
179
180  public:
181    DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff,
182            bool recv_snoops = false);
183
184    void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
185                   uint8_t *data, Tick delay, Request::Flags flag = 0);
186
187    bool dmaPending() { return pendingCount > 0; }
188
189    unsigned cacheBlockSize() const { return peerBlockSize(); }
190    unsigned int drain(Event *de);
191};
192
193/**
194 * This device is the base class which all devices senstive to an address range
195 * inherit from. There are three pure virtual functions which all devices must
196 * implement getAddrRanges(), read(), and write(). The magic do choose which
197 * mode we are in, etc is handled by the PioPort so the device doesn't have to
198 * bother.
199 */
200class PioDevice : public MemObject
201{
202  protected:
203    System *sys;
204
205    /** The pioPort that handles the requests for us and provides us requests
206     * that it sees. */
207    PioPort pioPort;
208
209    /**
210     * Every PIO device is obliged to provide an implementation that
211     * returns the address ranges the device responds to.
212     *
213     * @return a list of non-overlapping address ranges
214     */
215    virtual AddrRangeList getAddrRanges() = 0;
216
217    /** Pure virtual function that the device must implement. Called
218     * when a read command is recieved by the port.
219     * @param pkt Packet describing this request
220     * @return number of ticks it took to complete
221     */
222    virtual Tick read(PacketPtr pkt) = 0;
223
224    /** Pure virtual function that the device must implement. Called when a
225     * write command is recieved by the port.
226     * @param pkt Packet describing this request
227     * @return number of ticks it took to complete
228     */
229    virtual Tick write(PacketPtr pkt) = 0;
230
231  public:
232    typedef PioDeviceParams Params;
233    PioDevice(const Params *p);
234    virtual ~PioDevice();
235
236    const Params *
237    params() const
238    {
239        return dynamic_cast<const Params *>(_params);
240    }
241
242    virtual void init();
243
244    virtual unsigned int drain(Event *de);
245
246    virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1);
247
248    friend class PioPort;
249
250};
251
252class BasicPioDevice : public PioDevice
253{
254  protected:
255    /** Address that the device listens to. */
256    Addr pioAddr;
257
258    /** Size that the device's address range. */
259    Addr pioSize;
260
261    /** Delay that the device experinces on an access. */
262    Tick pioDelay;
263
264  public:
265    typedef BasicPioDeviceParams Params;
266    BasicPioDevice(const Params *p);
267
268    const Params *
269    params() const
270    {
271        return dynamic_cast<const Params *>(_params);
272    }
273
274    /**
275     * Determine the address ranges that this device responds to.
276     *
277     * @return a list of non-overlapping address ranges
278     */
279    virtual AddrRangeList getAddrRanges();
280
281};
282
283class DmaDevice : public PioDevice
284{
285   protected:
286    DmaPort dmaPort;
287
288  public:
289    typedef DmaDeviceParams Params;
290    DmaDevice(const Params *p);
291    virtual ~DmaDevice();
292
293    const Params *
294    params() const
295    {
296        return dynamic_cast<const Params *>(_params);
297    }
298
299    void dmaWrite(Addr addr, int size, Event *event, uint8_t *data,
300                  Tick delay = 0)
301    {
302        dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, delay);
303    }
304
305    void dmaRead(Addr addr, int size, Event *event, uint8_t *data,
306                 Tick delay = 0)
307    {
308        dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, delay);
309    }
310
311    bool dmaPending() { return dmaPort.dmaPending(); }
312
313    virtual void init();
314
315    virtual unsigned int drain(Event *de);
316
317    unsigned cacheBlockSize() const { return dmaPort.cacheBlockSize(); }
318
319    virtual MasterPort &getMasterPort(const std::string &if_name,
320                                      int idx = -1);
321
322    friend class DmaPort;
323};
324
325
326#endif // __DEV_IO_DEVICE_HH__
327