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 cacheable block in ownership state
108 assert(pkt
->req
->isUncacheable() ||
109 !(pkt
->memInhibitAsserted() && !pkt
->sharedAsserted()));
116 DmaDevice::DmaDevice(const Params
*p
)
117 : PioDevice(p
), dmaPort(this, sys
)
123 if (!dmaPort
.isConnected())
124 panic("DMA port of %s not connected to anything!", name());
129 DmaPort::drain(DrainManager
*dm
)
131 if (pendingCount
== 0)
134 DPRINTF(Drain
, "DmaPort not drained\n");
139 DmaPort::recvReqRetry()
141 assert(transmitList
.size());
146 DmaPort::dmaAction(Packet::Command cmd
, Addr addr
, int size
, Event
*event
,
147 uint8_t *data
, Tick delay
, Request::Flags flag
)
149 // one DMA request sender state for every action, that is then
150 // split into many requests and packets based on the block size,
151 // i.e. cache line size
152 DmaReqState
*reqState
= new DmaReqState(event
, size
, delay
);
154 // (functionality added for Table Walker statistics)
155 // We're only interested in this when there will only be one request.
156 // For simplicity, we return the last request, which would also be
157 // the only request in that case.
158 RequestPtr req
= NULL
;
160 DPRINTF(DMA
, "Starting DMA for addr: %#x size: %d sched: %d\n", addr
, size
,
161 event
? event
->scheduled() : -1);
162 for (ChunkGenerator
gen(addr
, size
, sys
->cacheLineSize());
163 !gen
.done(); gen
.next()) {
164 req
= new Request(gen
.addr(), gen
.size(), flag
, masterId
);
165 req
->taskId(ContextSwitchTaskId::DMA
);
166 PacketPtr pkt
= new Packet(req
, cmd
);
168 // Increment the data pointer on a write
170 pkt
->dataStatic(data
+ gen
.complete());
172 pkt
->senderState
= reqState
;
174 DPRINTF(DMA
, "--Queuing DMA for addr: %#x size: %d\n", gen
.addr(),
179 // in zero time also initiate the sending of the packets we have
180 // just created, for atomic this involves actually completing all
188 DmaPort::queueDma(PacketPtr pkt
)
190 transmitList
.push_back(pkt
);
192 // remember that we have another packet pending, this will only be
193 // decremented once a response comes back
198 DmaPort::trySendTimingReq()
200 // send the first packet on the transmit list and schedule the
201 // following send if it is successful
202 PacketPtr pkt
= transmitList
.front();
204 DPRINTF(DMA
, "Trying to send %s addr %#x\n", pkt
->cmdString(),
207 inRetry
= !sendTimingReq(pkt
);
209 transmitList
.pop_front();
210 DPRINTF(DMA
, "-- Done\n");
211 // if there is more to do, then do so
212 if (!transmitList
.empty())
213 // this should ultimately wait for as many cycles as the
214 // device needs to send the packet, but currently the port
215 // does not have any known width so simply wait a single
217 device
->schedule(sendEvent
, device
->clockEdge(Cycles(1)));
219 DPRINTF(DMA
, "-- Failed, waiting for retry\n");
222 DPRINTF(DMA
, "TransmitList: %d, inRetry: %d\n",
223 transmitList
.size(), inRetry
);
229 // some kind of selcetion between access methods
230 // more work is going to have to be done to make
231 // switching actually work
232 assert(transmitList
.size());
234 if (sys
->isTimingMode()) {
235 // if we are either waiting for a retry or are still waiting
236 // after sending the last packet, then do not proceed
237 if (inRetry
|| sendEvent
.scheduled()) {
238 DPRINTF(DMA
, "Can't send immediately, waiting to send\n");
243 } else if (sys
->isAtomicMode()) {
244 // send everything there is to send in zero time
245 while (!transmitList
.empty()) {
246 PacketPtr pkt
= transmitList
.front();
247 transmitList
.pop_front();
249 DPRINTF(DMA
, "Sending DMA for addr: %#x size: %d\n",
250 pkt
->req
->getPaddr(), pkt
->req
->getSize());
251 Tick lat
= sendAtomic(pkt
);
253 handleResp(pkt
, lat
);
256 panic("Unknown memory mode.");
260 DmaDevice::getMasterPort(const std::string
&if_name
, PortID idx
)
262 if (if_name
== "dma") {
265 return PioDevice::getMasterPort(if_name
, idx
);