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), drainEvent(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
;
89 device
->schedule(state
->completionEvent
, curTick() + delay
);
91 state
->completionEvent
->process();
96 // delete the request that we created and also the packet
100 // we might be drained at this point, if so signal the drain event
101 if (pendingCount
== 0 && drainEvent
) {
102 drainEvent
->process();
108 DmaPort::recvTimingResp(PacketPtr pkt
)
110 // We shouldn't ever get a block in ownership state
111 assert(!(pkt
->memInhibitAsserted() && !pkt
->sharedAsserted()));
118 DmaDevice::DmaDevice(const Params
*p
)
119 : PioDevice(p
), dmaPort(this, sys
)
125 if (!dmaPort
.isConnected())
126 panic("DMA port of %s not connected to anything!", name());
131 DmaDevice::drain(Event
*de
)
133 unsigned int count
= pioPort
.drain(de
) + dmaPort
.drain(de
);
135 changeState(Draining
);
137 changeState(Drained
);
142 DmaPort::drain(Event
*de
)
144 if (pendingCount
== 0)
147 DPRINTF(Drain
, "DmaPort not drained\n");
154 assert(transmitList
.size());
159 DmaPort::dmaAction(Packet::Command cmd
, Addr addr
, int size
, Event
*event
,
160 uint8_t *data
, Tick delay
, Request::Flags flag
)
162 // one DMA request sender state for every action, that is then
163 // split into many requests and packets based on the block size,
164 // i.e. cache line size
165 DmaReqState
*reqState
= new DmaReqState(event
, size
, delay
);
167 DPRINTF(DMA
, "Starting DMA for addr: %#x size: %d sched: %d\n", addr
, size
,
168 event
? event
->scheduled() : -1);
169 for (ChunkGenerator
gen(addr
, size
, peerBlockSize());
170 !gen
.done(); gen
.next()) {
171 Request
*req
= new Request(gen
.addr(), gen
.size(), flag
, masterId
);
172 PacketPtr pkt
= new Packet(req
, cmd
);
174 // Increment the data pointer on a write
176 pkt
->dataStatic(data
+ gen
.complete());
178 pkt
->senderState
= reqState
;
180 DPRINTF(DMA
, "--Queuing DMA for addr: %#x size: %d\n", gen
.addr(),
185 // in zero time also initiate the sending of the packets we have
186 // just created, for atomic this involves actually completing all
192 DmaPort::queueDma(PacketPtr pkt
)
194 transmitList
.push_back(pkt
);
196 // remember that we have another packet pending, this will only be
197 // decremented once a response comes back
202 DmaPort::trySendTimingReq()
204 // send the first packet on the transmit list and schedule the
205 // following send if it is successful
206 PacketPtr pkt
= transmitList
.front();
208 DPRINTF(DMA
, "Trying to send %s addr %#x\n", pkt
->cmdString(),
211 inRetry
= !sendTimingReq(pkt
);
213 transmitList
.pop_front();
214 DPRINTF(DMA
, "-- Done\n");
215 // if there is more to do, then do so
216 if (!transmitList
.empty())
217 // this should ultimately wait for as many cycles as the
218 // device needs to send the packet, but currently the port
219 // does not have any known width so simply wait a single
221 device
->schedule(sendEvent
, device
->clockEdge(Cycles(1)));
223 DPRINTF(DMA
, "-- Failed, waiting for retry\n");
226 DPRINTF(DMA
, "TransmitList: %d, inRetry: %d\n",
227 transmitList
.size(), inRetry
);
233 // some kind of selcetion between access methods
234 // more work is going to have to be done to make
235 // switching actually work
236 assert(transmitList
.size());
238 Enums::MemoryMode state
= sys
->getMemoryMode();
239 if (state
== Enums::timing
) {
240 // if we are either waiting for a retry or are still waiting
241 // after sending the last packet, then do not proceed
242 if (inRetry
|| sendEvent
.scheduled()) {
243 DPRINTF(DMA
, "Can't send immediately, waiting to send\n");
248 } else if (state
== Enums::atomic
) {
249 // send everything there is to send in zero time
250 while (!transmitList
.empty()) {
251 PacketPtr pkt
= transmitList
.front();
252 transmitList
.pop_front();
254 DPRINTF(DMA
, "Sending DMA for addr: %#x size: %d\n",
255 pkt
->req
->getPaddr(), pkt
->req
->getSize());
256 Tick lat
= sendAtomic(pkt
);
258 handleResp(pkt
, lat
);
261 panic("Unknown memory mode.");
265 DmaDevice::getMasterPort(const std::string
&if_name
, PortID idx
)
267 if (if_name
== "dma") {
270 return PioDevice::getMasterPort(if_name
, idx
);