2 * Copyright (c) 2012 ARM Limited
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.
14 * Copyright (c) 2006 The Regents of The University of Michigan
15 * All rights reserved.
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.
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.
45 #include "base/chunk_generator.hh"
46 #include "debug/DMA.hh"
47 #include "debug/Drain.hh"
48 #include "dev/dma_device.hh"
49 #include "sim/system.hh"
51 DmaPort::DmaPort(MemObject
*dev
, System
*s
)
52 : MasterPort(dev
->name() + ".dma", dev
), device(dev
), sendEvent(this),
53 sys(s
), masterId(s
->getMasterId(dev
->name())),
54 pendingCount(0), drainManager(NULL
),
59 DmaPort::handleResp(PacketPtr pkt
, Tick delay
)
61 // should always see a response with a sender state
62 assert(pkt
->isResponse());
64 // get the DMA sender state
65 DmaReqState
*state
= dynamic_cast<DmaReqState
*>(pkt
->senderState
);
68 DPRINTF(DMA
, "Received response %s for addr: %#x size: %d nb: %d," \
69 " tot: %d sched %d\n",
70 pkt
->cmdString(), pkt
->getAddr(), pkt
->req
->getSize(),
71 state
->numBytes
, state
->totBytes
,
72 state
->completionEvent
?
73 state
->completionEvent
->scheduled() : 0);
75 assert(pendingCount
!= 0);
78 // update the number of bytes received based on the request rather
79 // than the packet as the latter could be rounded up to line sizes
80 state
->numBytes
+= pkt
->req
->getSize();
81 assert(state
->totBytes
>= state
->numBytes
);
83 // if we have reached the total number of bytes for this DMA
84 // request, then signal the completion and delete the sate
85 if (state
->totBytes
== state
->numBytes
) {
86 if (state
->completionEvent
) {
87 delay
+= state
->delay
;
88 device
->schedule(state
->completionEvent
, curTick() + delay
);
93 // delete the request that we created and also the packet
97 // we might be drained at this point, if so signal the drain event
98 if (pendingCount
== 0 && drainManager
) {
99 drainManager
->signalDrainDone();
105 DmaPort::recvTimingResp(PacketPtr pkt
)
107 // We shouldn't ever get a block in ownership state
108 assert(!(pkt
->memInhibitAsserted() && !pkt
->sharedAsserted()));
115 DmaDevice::DmaDevice(const Params
*p
)
116 : PioDevice(p
), dmaPort(this, sys
)
122 if (!dmaPort
.isConnected())
123 panic("DMA port of %s not connected to anything!", name());
128 DmaDevice::drain(DrainManager
*dm
)
130 unsigned int count
= pioPort
.drain(dm
) + dmaPort
.drain(dm
);
132 setDrainState(Drainable::Draining
);
134 setDrainState(Drainable::Drained
);
139 DmaPort::drain(DrainManager
*dm
)
141 if (pendingCount
== 0)
144 DPRINTF(Drain
, "DmaPort not drained\n");
151 assert(transmitList
.size());
156 DmaPort::dmaAction(Packet::Command cmd
, Addr addr
, int size
, Event
*event
,
157 uint8_t *data
, Tick delay
, Request::Flags flag
)
159 // one DMA request sender state for every action, that is then
160 // split into many requests and packets based on the block size,
161 // i.e. cache line size
162 DmaReqState
*reqState
= new DmaReqState(event
, size
, delay
);
164 DPRINTF(DMA
, "Starting DMA for addr: %#x size: %d sched: %d\n", addr
, size
,
165 event
? event
->scheduled() : -1);
166 for (ChunkGenerator
gen(addr
, size
, peerBlockSize());
167 !gen
.done(); gen
.next()) {
168 Request
*req
= new Request(gen
.addr(), gen
.size(), flag
, masterId
);
169 PacketPtr pkt
= new Packet(req
, cmd
);
171 // Increment the data pointer on a write
173 pkt
->dataStatic(data
+ gen
.complete());
175 pkt
->senderState
= reqState
;
177 DPRINTF(DMA
, "--Queuing DMA for addr: %#x size: %d\n", gen
.addr(),
182 // in zero time also initiate the sending of the packets we have
183 // just created, for atomic this involves actually completing all
189 DmaPort::queueDma(PacketPtr pkt
)
191 transmitList
.push_back(pkt
);
193 // remember that we have another packet pending, this will only be
194 // decremented once a response comes back
199 DmaPort::trySendTimingReq()
201 // send the first packet on the transmit list and schedule the
202 // following send if it is successful
203 PacketPtr pkt
= transmitList
.front();
205 DPRINTF(DMA
, "Trying to send %s addr %#x\n", pkt
->cmdString(),
208 inRetry
= !sendTimingReq(pkt
);
210 transmitList
.pop_front();
211 DPRINTF(DMA
, "-- Done\n");
212 // if there is more to do, then do so
213 if (!transmitList
.empty())
214 // this should ultimately wait for as many cycles as the
215 // device needs to send the packet, but currently the port
216 // does not have any known width so simply wait a single
218 device
->schedule(sendEvent
, device
->clockEdge(Cycles(1)));
220 DPRINTF(DMA
, "-- Failed, waiting for retry\n");
223 DPRINTF(DMA
, "TransmitList: %d, inRetry: %d\n",
224 transmitList
.size(), inRetry
);
230 // some kind of selcetion between access methods
231 // more work is going to have to be done to make
232 // switching actually work
233 assert(transmitList
.size());
235 if (sys
->isTimingMode()) {
236 // if we are either waiting for a retry or are still waiting
237 // after sending the last packet, then do not proceed
238 if (inRetry
|| sendEvent
.scheduled()) {
239 DPRINTF(DMA
, "Can't send immediately, waiting to send\n");
244 } else if (sys
->isAtomicMode()) {
245 // send everything there is to send in zero time
246 while (!transmitList
.empty()) {
247 PacketPtr pkt
= transmitList
.front();
248 transmitList
.pop_front();
250 DPRINTF(DMA
, "Sending DMA for addr: %#x size: %d\n",
251 pkt
->req
->getPaddr(), pkt
->req
->getSize());
252 Tick lat
= sendAtomic(pkt
);
254 handleResp(pkt
, lat
);
257 panic("Unknown memory mode.");
261 DmaDevice::getMasterPort(const std::string
&if_name
, PortID idx
)
263 if (if_name
== "dma") {
266 return PioDevice::getMasterPort(if_name
, idx
);