dma_device.hh revision 8948
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 recvTiming(PacketPtr pkt);
150
151    virtual bool recvTimingSnoop(PacketPtr pkt)
152    {
153        if (!recvSnoops)
154            panic("%s was not expecting a snoop\n", name());
155        return true;
156    }
157
158    virtual Tick recvAtomicSnoop(PacketPtr pkt)
159    {
160        if (!recvSnoops)
161            panic("%s was not expecting a snoop\n", name());
162        return 0;
163    }
164
165    virtual void recvFunctionalSnoop(PacketPtr pkt)
166    {
167        if (!recvSnoops)
168            panic("%s was not expecting a snoop\n", name());
169    }
170
171    virtual void recvRetry() ;
172
173    virtual bool isSnooping() const { return recvSnoops; }
174
175    void queueDma(PacketPtr pkt, bool front = false);
176    void sendDma();
177
178    /** event to give us a kick every time we backoff time is reached. */
179    EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent;
180
181  public:
182    DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff,
183            bool recv_snoops = false);
184
185    void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
186                   uint8_t *data, Tick delay, Request::Flags flag = 0);
187
188    bool dmaPending() { return pendingCount > 0; }
189
190    unsigned cacheBlockSize() const { return peerBlockSize(); }
191    unsigned int drain(Event *de);
192};
193
194/**
195 * This device is the base class which all devices senstive to an address range
196 * inherit from. There are three pure virtual functions which all devices must
197 * implement getAddrRanges(), read(), and write(). The magic do choose which
198 * mode we are in, etc is handled by the PioPort so the device doesn't have to
199 * bother.
200 */
201class PioDevice : public MemObject
202{
203  protected:
204    System *sys;
205
206    /** The pioPort that handles the requests for us and provides us requests
207     * that it sees. */
208    PioPort pioPort;
209
210    /**
211     * Every PIO device is obliged to provide an implementation that
212     * returns the address ranges the device responds to.
213     *
214     * @return a list of non-overlapping address ranges
215     */
216    virtual AddrRangeList getAddrRanges() = 0;
217
218    /** Pure virtual function that the device must implement. Called
219     * when a read command is recieved by the port.
220     * @param pkt Packet describing this request
221     * @return number of ticks it took to complete
222     */
223    virtual Tick read(PacketPtr pkt) = 0;
224
225    /** Pure virtual function that the device must implement. Called when a
226     * write command is recieved by the port.
227     * @param pkt Packet describing this request
228     * @return number of ticks it took to complete
229     */
230    virtual Tick write(PacketPtr pkt) = 0;
231
232  public:
233    typedef PioDeviceParams Params;
234    PioDevice(const Params *p);
235    virtual ~PioDevice();
236
237    const Params *
238    params() const
239    {
240        return dynamic_cast<const Params *>(_params);
241    }
242
243    virtual void init();
244
245    virtual unsigned int drain(Event *de);
246
247    virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1);
248
249    friend class PioPort;
250
251};
252
253class BasicPioDevice : public PioDevice
254{
255  protected:
256    /** Address that the device listens to. */
257    Addr pioAddr;
258
259    /** Size that the device's address range. */
260    Addr pioSize;
261
262    /** Delay that the device experinces on an access. */
263    Tick pioDelay;
264
265  public:
266    typedef BasicPioDeviceParams Params;
267    BasicPioDevice(const Params *p);
268
269    const Params *
270    params() const
271    {
272        return dynamic_cast<const Params *>(_params);
273    }
274
275    /**
276     * Determine the address ranges that this device responds to.
277     *
278     * @return a list of non-overlapping address ranges
279     */
280    virtual AddrRangeList getAddrRanges();
281
282};
283
284class DmaDevice : public PioDevice
285{
286   protected:
287    DmaPort dmaPort;
288
289  public:
290    typedef DmaDeviceParams Params;
291    DmaDevice(const Params *p);
292    virtual ~DmaDevice();
293
294    const Params *
295    params() const
296    {
297        return dynamic_cast<const Params *>(_params);
298    }
299
300    void dmaWrite(Addr addr, int size, Event *event, uint8_t *data,
301                  Tick delay = 0)
302    {
303        dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, delay);
304    }
305
306    void dmaRead(Addr addr, int size, Event *event, uint8_t *data,
307                 Tick delay = 0)
308    {
309        dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, delay);
310    }
311
312    bool dmaPending() { return dmaPort.dmaPending(); }
313
314    virtual void init();
315
316    virtual unsigned int drain(Event *de);
317
318    unsigned cacheBlockSize() const { return dmaPort.cacheBlockSize(); }
319
320    virtual MasterPort &getMasterPort(const std::string &if_name,
321                                      int idx = -1);
322
323    friend class DmaPort;
324};
325
326
327#endif // __DEV_IO_DEVICE_HH__
328