2 * Copyright (c) 2006 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "base/chunk_generator.hh"
33 #include "base/trace.hh"
34 #include "debug/BusAddrRanges.hh"
35 #include "debug/DMA.hh"
36 #include "dev/io_device.hh"
37 #include "sim/system.hh"
39 PioPort::PioPort(PioDevice
*dev
, System
*s
, std::string pname
)
40 : SimpleTimingPort(dev
->name() + pname
, dev
), device(dev
)
45 PioPort::recvAtomic(PacketPtr pkt
)
47 return pkt
->isRead() ? device
->read(pkt
) : device
->write(pkt
);
51 PioPort::getAddrRanges()
53 return device
->getAddrRanges();
57 PioDevice::PioDevice(const Params
*p
)
58 : MemObject(p
), sys(p
->system
), pioPort(this, sys
)
61 PioDevice::~PioDevice()
68 if (!pioPort
.isConnected())
69 panic("Pio port of %s not connected to anything!", name());
70 pioPort
.sendRangeChange();
74 PioDevice::getPort(const std::string
&if_name
, int idx
)
76 if (if_name
== "pio") {
79 panic("PioDevice %s has no port named %s\n", name(), if_name
);
84 PioDevice::drain(Event
*de
)
87 count
= pioPort
.drain(de
);
89 changeState(Draining
);
95 BasicPioDevice::BasicPioDevice(const Params
*p
)
96 : PioDevice(p
), pioAddr(p
->pio_addr
), pioSize(0),
97 pioDelay(p
->pio_latency
)
101 BasicPioDevice::getAddrRanges()
103 assert(pioSize
!= 0);
104 AddrRangeList ranges
;
105 DPRINTF(BusAddrRanges
, "registering range: %#x-%#x\n", pioAddr
, pioSize
);
106 ranges
.push_back(RangeSize(pioAddr
, pioSize
));
111 DmaPort::DmaPort(MemObject
*dev
, System
*s
, Tick min_backoff
, Tick max_backoff
,
113 : Port(dev
->name() + "-dmaport", dev
), device(dev
), sys(s
),
114 masterId(s
->getMasterId(dev
->name())),
115 pendingCount(0), actionInProgress(0), drainEvent(NULL
),
116 backoffTime(0), minBackoffDelay(min_backoff
),
117 maxBackoffDelay(max_backoff
), inRetry(false), recvSnoops(recv_snoops
),
122 DmaPort::recvTiming(PacketPtr pkt
)
124 if (pkt
->wasNacked()) {
125 DPRINTF(DMA
, "Received nacked %s addr %#x\n",
126 pkt
->cmdString(), pkt
->getAddr());
128 if (backoffTime
< minBackoffDelay
)
129 backoffTime
= minBackoffDelay
;
130 else if (backoffTime
< maxBackoffDelay
)
133 device
->reschedule(backoffEvent
, curTick() + backoffTime
, true);
135 DPRINTF(DMA
, "Backoff time set to %d ticks\n", backoffTime
);
139 } else if (pkt
->isRequest() && recvSnoops
) {
141 } else if (pkt
->senderState
) {
145 DPRINTF(DMA
, "Received response %s addr %#x size %#x\n",
146 pkt
->cmdString(), pkt
->getAddr(), pkt
->req
->getSize());
147 state
= dynamic_cast<DmaReqState
*>(pkt
->senderState
);
150 assert(pendingCount
>= 0);
153 // We shouldn't ever get a block in ownership state
154 assert(!(pkt
->memInhibitAsserted() && !pkt
->sharedAsserted()));
156 state
->numBytes
+= pkt
->req
->getSize();
157 assert(state
->totBytes
>= state
->numBytes
);
158 if (state
->totBytes
== state
->numBytes
) {
159 if (state
->completionEvent
) {
161 device
->schedule(state
->completionEvent
,
162 curTick() + state
->delay
);
164 state
->completionEvent
->process();
171 if (pendingCount
== 0 && drainEvent
) {
172 drainEvent
->process();
176 panic("Got packet without sender state... huh?\n");
182 DmaDevice::DmaDevice(const Params
*p
)
183 : PioDevice(p
), dmaPort(this, sys
, params()->min_backoff_delay
,
184 params()->max_backoff_delay
)
190 if (!dmaPort
.isConnected())
191 panic("DMA port of %s not connected to anything!", name());
196 DmaDevice::drain(Event
*de
)
199 count
= pioPort
.drain(de
) + dmaPort
.drain(de
);
201 changeState(Draining
);
203 changeState(Drained
);
208 DmaPort::drain(Event
*de
)
210 if (pendingCount
== 0)
220 assert(transmitList
.size());
223 PacketPtr pkt
= transmitList
.front();
224 DPRINTF(DMA
, "Retry on %s addr %#x\n",
225 pkt
->cmdString(), pkt
->getAddr());
226 result
= sendTiming(pkt
);
228 DPRINTF(DMA
, "-- Done\n");
229 transmitList
.pop_front();
233 DPRINTF(DMA
, "-- Failed, queued\n");
235 } while (!backoffTime
&& result
&& transmitList
.size());
237 if (transmitList
.size() && backoffTime
&& !inRetry
) {
238 DPRINTF(DMA
, "Scheduling backoff for %d\n", curTick()+backoffTime
);
239 if (!backoffEvent
.scheduled())
240 device
->schedule(backoffEvent
, backoffTime
+ curTick());
242 DPRINTF(DMA
, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n",
243 transmitList
.size(), backoffTime
, inRetry
,
244 backoffEvent
.scheduled());
249 DmaPort::dmaAction(Packet::Command cmd
, Addr addr
, int size
, Event
*event
,
250 uint8_t *data
, Tick delay
, Request::Flags flag
)
252 assert(device
->getState() == SimObject::Running
);
254 DmaReqState
*reqState
= new DmaReqState(event
, this, size
, delay
);
257 DPRINTF(DMA
, "Starting DMA for addr: %#x size: %d sched: %d\n", addr
, size
,
258 event
? event
->scheduled() : -1 );
259 for (ChunkGenerator
gen(addr
, size
, peerBlockSize());
260 !gen
.done(); gen
.next()) {
261 Request
*req
= new Request(gen
.addr(), gen
.size(), flag
, masterId
);
262 PacketPtr pkt
= new Packet(req
, cmd
, Packet::Broadcast
);
264 // Increment the data pointer on a write
266 pkt
->dataStatic(data
+ gen
.complete());
268 pkt
->senderState
= reqState
;
270 assert(pendingCount
>= 0);
272 DPRINTF(DMA
, "--Queuing DMA for addr: %#x size: %d\n", gen
.addr(),
280 DmaPort::queueDma(PacketPtr pkt
, bool front
)
284 transmitList
.push_front(pkt
);
286 transmitList
.push_back(pkt
);
294 // some kind of selction between access methods
295 // more work is going to have to be done to make
296 // switching actually work
297 assert(transmitList
.size());
298 PacketPtr pkt
= transmitList
.front();
300 Enums::MemoryMode state
= sys
->getMemoryMode();
301 if (state
== Enums::timing
) {
302 if (backoffEvent
.scheduled() || inRetry
) {
303 DPRINTF(DMA
, "Can't send immediately, waiting for retry or backoff timer\n");
307 DPRINTF(DMA
, "Attempting to send %s addr %#x\n",
308 pkt
->cmdString(), pkt
->getAddr());
312 result
= sendTiming(pkt
);
314 transmitList
.pop_front();
315 DPRINTF(DMA
, "-- Done\n");
318 DPRINTF(DMA
, "-- Failed: queued\n");
320 } while (result
&& !backoffTime
&& transmitList
.size());
322 if (transmitList
.size() && backoffTime
&& !inRetry
&&
323 !backoffEvent
.scheduled()) {
324 DPRINTF(DMA
, "-- Scheduling backoff timer for %d\n",
325 backoffTime
+curTick());
326 device
->schedule(backoffEvent
, backoffTime
+ curTick());
328 } else if (state
== Enums::atomic
) {
329 transmitList
.pop_front();
332 DPRINTF(DMA
, "--Sending DMA for addr: %#x size: %d\n",
333 pkt
->req
->getPaddr(), pkt
->req
->getSize());
334 lat
= sendAtomic(pkt
);
335 assert(pkt
->senderState
);
336 DmaReqState
*state
= dynamic_cast<DmaReqState
*>(pkt
->senderState
);
338 state
->numBytes
+= pkt
->req
->getSize();
340 DPRINTF(DMA
, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n",
341 pkt
->req
->getPaddr(), pkt
->req
->getSize(), state
->numBytes
,
343 state
->completionEvent
? state
->completionEvent
->scheduled() : 0 );
345 if (state
->totBytes
== state
->numBytes
) {
346 if (state
->completionEvent
) {
347 assert(!state
->completionEvent
->scheduled());
348 device
->schedule(state
->completionEvent
,
349 curTick() + lat
+ state
->delay
);
355 assert(pendingCount
>= 0);
358 if (pendingCount
== 0 && drainEvent
) {
359 drainEvent
->process();
364 panic("Unknown memory command state.");
367 DmaDevice::~DmaDevice()
373 DmaDevice::getPort(const std::string
&if_name
, int idx
)
375 if (if_name
== "dma") {
378 return PioDevice::getPort(if_name
, idx
);