io_device.cc (8975:7f36d4436074) io_device.cc (9015:7f4d25789dc4)
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) 2006 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#include "base/chunk_generator.hh"
45#include "base/trace.hh"
46#include "debug/BusAddrRanges.hh"
47#include "debug/DMA.hh"
48#include "dev/io_device.hh"
49#include "sim/system.hh"
50
51PioPort::PioPort(PioDevice *dev)
52 : SimpleTimingPort(dev->name() + "-pioport", dev), device(dev)
53{
54}
55
56
57Tick
58PioPort::recvAtomic(PacketPtr pkt)
59{
60 return pkt->isRead() ? device->read(pkt) : device->write(pkt);
61}
62
63AddrRangeList
64PioPort::getAddrRanges()
65{
66 return device->getAddrRanges();
67}
68
69
70PioDevice::PioDevice(const Params *p)
71 : MemObject(p), sys(p->system), pioPort(this)
72{}
73
74PioDevice::~PioDevice()
75{
76}
77
78void
79PioDevice::init()
80{
81 if (!pioPort.isConnected())
82 panic("Pio port of %s not connected to anything!", name());
83 pioPort.sendRangeChange();
84}
85
86SlavePort &
87PioDevice::getSlavePort(const std::string &if_name, int idx)
88{
89 if (if_name == "pio") {
90 return pioPort;
91 }
92 return MemObject::getSlavePort(if_name, idx);
93}
94
95unsigned int
96PioDevice::drain(Event *de)
97{
98 unsigned int count;
99 count = pioPort.drain(de);
100 if (count)
101 changeState(Draining);
102 else
103 changeState(Drained);
104 return count;
105}
106
107BasicPioDevice::BasicPioDevice(const Params *p)
108 : PioDevice(p), pioAddr(p->pio_addr), pioSize(0),
109 pioDelay(p->pio_latency)
110{}
111
112AddrRangeList
113BasicPioDevice::getAddrRanges()
114{
115 assert(pioSize != 0);
116 AddrRangeList ranges;
117 DPRINTF(BusAddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
118 ranges.push_back(RangeSize(pioAddr, pioSize));
119 return ranges;
120}
121
122
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) 2006 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#include "base/chunk_generator.hh"
45#include "base/trace.hh"
46#include "debug/BusAddrRanges.hh"
47#include "debug/DMA.hh"
48#include "dev/io_device.hh"
49#include "sim/system.hh"
50
51PioPort::PioPort(PioDevice *dev)
52 : SimpleTimingPort(dev->name() + "-pioport", dev), device(dev)
53{
54}
55
56
57Tick
58PioPort::recvAtomic(PacketPtr pkt)
59{
60 return pkt->isRead() ? device->read(pkt) : device->write(pkt);
61}
62
63AddrRangeList
64PioPort::getAddrRanges()
65{
66 return device->getAddrRanges();
67}
68
69
70PioDevice::PioDevice(const Params *p)
71 : MemObject(p), sys(p->system), pioPort(this)
72{}
73
74PioDevice::~PioDevice()
75{
76}
77
78void
79PioDevice::init()
80{
81 if (!pioPort.isConnected())
82 panic("Pio port of %s not connected to anything!", name());
83 pioPort.sendRangeChange();
84}
85
86SlavePort &
87PioDevice::getSlavePort(const std::string &if_name, int idx)
88{
89 if (if_name == "pio") {
90 return pioPort;
91 }
92 return MemObject::getSlavePort(if_name, idx);
93}
94
95unsigned int
96PioDevice::drain(Event *de)
97{
98 unsigned int count;
99 count = pioPort.drain(de);
100 if (count)
101 changeState(Draining);
102 else
103 changeState(Drained);
104 return count;
105}
106
107BasicPioDevice::BasicPioDevice(const Params *p)
108 : PioDevice(p), pioAddr(p->pio_addr), pioSize(0),
109 pioDelay(p->pio_latency)
110{}
111
112AddrRangeList
113BasicPioDevice::getAddrRanges()
114{
115 assert(pioSize != 0);
116 AddrRangeList ranges;
117 DPRINTF(BusAddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
118 ranges.push_back(RangeSize(pioAddr, pioSize));
119 return ranges;
120}
121
122
123DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff,
124 bool recv_snoops)
125 : MasterPort(dev->name() + "-dmaport", dev), device(dev), sys(s),
123DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff)
124 : MasterPort(dev->name() + "-dma", dev), device(dev), sys(s),
126 masterId(s->getMasterId(dev->name())),
127 pendingCount(0), actionInProgress(0), drainEvent(NULL),
128 backoffTime(0), minBackoffDelay(min_backoff),
125 masterId(s->getMasterId(dev->name())),
126 pendingCount(0), actionInProgress(0), drainEvent(NULL),
127 backoffTime(0), minBackoffDelay(min_backoff),
129 maxBackoffDelay(max_backoff), inRetry(false), recvSnoops(recv_snoops),
128 maxBackoffDelay(max_backoff), inRetry(false),
130 backoffEvent(this)
131{ }
132
133bool
134DmaPort::recvTimingResp(PacketPtr pkt)
135{
136 if (pkt->wasNacked()) {
137 DPRINTF(DMA, "Received nacked %s addr %#x\n",
138 pkt->cmdString(), pkt->getAddr());
139
140 if (backoffTime < minBackoffDelay)
141 backoffTime = minBackoffDelay;
142 else if (backoffTime < maxBackoffDelay)
143 backoffTime <<= 1;
144
145 device->reschedule(backoffEvent, curTick() + backoffTime, true);
146
147 DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime);
148
149 pkt->reinitNacked();
150 queueDma(pkt, true);
151 } else if (pkt->senderState) {
152 DmaReqState *state;
153 backoffTime >>= 2;
154
155 DPRINTF(DMA, "Received response %s addr %#x size %#x\n",
156 pkt->cmdString(), pkt->getAddr(), pkt->req->getSize());
157 state = dynamic_cast<DmaReqState*>(pkt->senderState);
158 pendingCount--;
159
160 assert(pendingCount >= 0);
161 assert(state);
162
163 // We shouldn't ever get a block in ownership state
164 assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
165
166 state->numBytes += pkt->req->getSize();
167 assert(state->totBytes >= state->numBytes);
168 if (state->totBytes == state->numBytes) {
169 if (state->completionEvent) {
170 if (state->delay)
171 device->schedule(state->completionEvent,
172 curTick() + state->delay);
173 else
174 state->completionEvent->process();
175 }
176 delete state;
177 }
178 delete pkt->req;
179 delete pkt;
180
181 if (pendingCount == 0 && drainEvent) {
182 drainEvent->process();
183 drainEvent = NULL;
184 }
185 } else {
186 panic("Got packet without sender state... huh?\n");
187 }
188
189 return true;
190}
191
192DmaDevice::DmaDevice(const Params *p)
193 : PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay,
194 params()->max_backoff_delay)
195{ }
196
197void
198DmaDevice::init()
199{
200 if (!dmaPort.isConnected())
201 panic("DMA port of %s not connected to anything!", name());
202 PioDevice::init();
203}
204
205unsigned int
206DmaDevice::drain(Event *de)
207{
208 unsigned int count;
209 count = pioPort.drain(de) + dmaPort.drain(de);
210 if (count)
211 changeState(Draining);
212 else
213 changeState(Drained);
214 return count;
215}
216
217unsigned int
218DmaPort::drain(Event *de)
219{
220 if (pendingCount == 0)
221 return 0;
222 drainEvent = de;
223 return 1;
224}
225
226
227void
228DmaPort::recvRetry()
229{
230 assert(transmitList.size());
231 bool result = true;
232 do {
233 PacketPtr pkt = transmitList.front();
234 DPRINTF(DMA, "Retry on %s addr %#x\n",
235 pkt->cmdString(), pkt->getAddr());
236 result = sendTimingReq(pkt);
237 if (result) {
238 DPRINTF(DMA, "-- Done\n");
239 transmitList.pop_front();
240 inRetry = false;
241 } else {
242 inRetry = true;
243 DPRINTF(DMA, "-- Failed, queued\n");
244 }
245 } while (!backoffTime && result && transmitList.size());
246
247 if (transmitList.size() && backoffTime && !inRetry) {
248 DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime);
249 if (!backoffEvent.scheduled())
250 device->schedule(backoffEvent, backoffTime + curTick());
251 }
252 DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n",
253 transmitList.size(), backoffTime, inRetry,
254 backoffEvent.scheduled());
255}
256
257
258void
259DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
260 uint8_t *data, Tick delay, Request::Flags flag)
261{
262 assert(device->getState() == SimObject::Running);
263
264 DmaReqState *reqState = new DmaReqState(event, this, size, delay);
265
266
267 DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
268 event ? event->scheduled() : -1 );
269 for (ChunkGenerator gen(addr, size, peerBlockSize());
270 !gen.done(); gen.next()) {
271 Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
272 PacketPtr pkt = new Packet(req, cmd);
273
274 // Increment the data pointer on a write
275 if (data)
276 pkt->dataStatic(data + gen.complete());
277
278 pkt->senderState = reqState;
279
280 assert(pendingCount >= 0);
281 pendingCount++;
282 DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
283 gen.size());
284 queueDma(pkt);
285 }
286
287}
288
289void
290DmaPort::queueDma(PacketPtr pkt, bool front)
291{
292
293 if (front)
294 transmitList.push_front(pkt);
295 else
296 transmitList.push_back(pkt);
297 sendDma();
298}
299
300
301void
302DmaPort::sendDma()
303{
304 // some kind of selction between access methods
305 // more work is going to have to be done to make
306 // switching actually work
307 assert(transmitList.size());
308 PacketPtr pkt = transmitList.front();
309
310 Enums::MemoryMode state = sys->getMemoryMode();
311 if (state == Enums::timing) {
312 if (backoffEvent.scheduled() || inRetry) {
313 DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n");
314 return;
315 }
316
317 DPRINTF(DMA, "Attempting to send %s addr %#x\n",
318 pkt->cmdString(), pkt->getAddr());
319
320 bool result;
321 do {
322 result = sendTimingReq(pkt);
323 if (result) {
324 transmitList.pop_front();
325 DPRINTF(DMA, "-- Done\n");
326 } else {
327 inRetry = true;
328 DPRINTF(DMA, "-- Failed: queued\n");
329 }
330 } while (result && !backoffTime && transmitList.size());
331
332 if (transmitList.size() && backoffTime && !inRetry &&
333 !backoffEvent.scheduled()) {
334 DPRINTF(DMA, "-- Scheduling backoff timer for %d\n",
335 backoffTime+curTick());
336 device->schedule(backoffEvent, backoffTime + curTick());
337 }
338 } else if (state == Enums::atomic) {
339 transmitList.pop_front();
340
341 Tick lat;
342 DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n",
343 pkt->req->getPaddr(), pkt->req->getSize());
344 lat = sendAtomic(pkt);
345 assert(pkt->senderState);
346 DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
347 assert(state);
348 state->numBytes += pkt->req->getSize();
349
350 DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n",
351 pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes,
352 state->totBytes,
353 state->completionEvent ? state->completionEvent->scheduled() : 0 );
354
355 if (state->totBytes == state->numBytes) {
356 if (state->completionEvent) {
357 assert(!state->completionEvent->scheduled());
358 device->schedule(state->completionEvent,
359 curTick() + lat + state->delay);
360 }
361 delete state;
362 delete pkt->req;
363 }
364 pendingCount--;
365 assert(pendingCount >= 0);
366 delete pkt;
367
368 if (pendingCount == 0 && drainEvent) {
369 drainEvent->process();
370 drainEvent = NULL;
371 }
372
373 } else
374 panic("Unknown memory command state.");
375}
376
377DmaDevice::~DmaDevice()
378{
379}
380
381
382MasterPort &
383DmaDevice::getMasterPort(const std::string &if_name, int idx)
384{
385 if (if_name == "dma") {
386 return dmaPort;
387 }
388 return PioDevice::getMasterPort(if_name, idx);
389}
390
129 backoffEvent(this)
130{ }
131
132bool
133DmaPort::recvTimingResp(PacketPtr pkt)
134{
135 if (pkt->wasNacked()) {
136 DPRINTF(DMA, "Received nacked %s addr %#x\n",
137 pkt->cmdString(), pkt->getAddr());
138
139 if (backoffTime < minBackoffDelay)
140 backoffTime = minBackoffDelay;
141 else if (backoffTime < maxBackoffDelay)
142 backoffTime <<= 1;
143
144 device->reschedule(backoffEvent, curTick() + backoffTime, true);
145
146 DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime);
147
148 pkt->reinitNacked();
149 queueDma(pkt, true);
150 } else if (pkt->senderState) {
151 DmaReqState *state;
152 backoffTime >>= 2;
153
154 DPRINTF(DMA, "Received response %s addr %#x size %#x\n",
155 pkt->cmdString(), pkt->getAddr(), pkt->req->getSize());
156 state = dynamic_cast<DmaReqState*>(pkt->senderState);
157 pendingCount--;
158
159 assert(pendingCount >= 0);
160 assert(state);
161
162 // We shouldn't ever get a block in ownership state
163 assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
164
165 state->numBytes += pkt->req->getSize();
166 assert(state->totBytes >= state->numBytes);
167 if (state->totBytes == state->numBytes) {
168 if (state->completionEvent) {
169 if (state->delay)
170 device->schedule(state->completionEvent,
171 curTick() + state->delay);
172 else
173 state->completionEvent->process();
174 }
175 delete state;
176 }
177 delete pkt->req;
178 delete pkt;
179
180 if (pendingCount == 0 && drainEvent) {
181 drainEvent->process();
182 drainEvent = NULL;
183 }
184 } else {
185 panic("Got packet without sender state... huh?\n");
186 }
187
188 return true;
189}
190
191DmaDevice::DmaDevice(const Params *p)
192 : PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay,
193 params()->max_backoff_delay)
194{ }
195
196void
197DmaDevice::init()
198{
199 if (!dmaPort.isConnected())
200 panic("DMA port of %s not connected to anything!", name());
201 PioDevice::init();
202}
203
204unsigned int
205DmaDevice::drain(Event *de)
206{
207 unsigned int count;
208 count = pioPort.drain(de) + dmaPort.drain(de);
209 if (count)
210 changeState(Draining);
211 else
212 changeState(Drained);
213 return count;
214}
215
216unsigned int
217DmaPort::drain(Event *de)
218{
219 if (pendingCount == 0)
220 return 0;
221 drainEvent = de;
222 return 1;
223}
224
225
226void
227DmaPort::recvRetry()
228{
229 assert(transmitList.size());
230 bool result = true;
231 do {
232 PacketPtr pkt = transmitList.front();
233 DPRINTF(DMA, "Retry on %s addr %#x\n",
234 pkt->cmdString(), pkt->getAddr());
235 result = sendTimingReq(pkt);
236 if (result) {
237 DPRINTF(DMA, "-- Done\n");
238 transmitList.pop_front();
239 inRetry = false;
240 } else {
241 inRetry = true;
242 DPRINTF(DMA, "-- Failed, queued\n");
243 }
244 } while (!backoffTime && result && transmitList.size());
245
246 if (transmitList.size() && backoffTime && !inRetry) {
247 DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime);
248 if (!backoffEvent.scheduled())
249 device->schedule(backoffEvent, backoffTime + curTick());
250 }
251 DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n",
252 transmitList.size(), backoffTime, inRetry,
253 backoffEvent.scheduled());
254}
255
256
257void
258DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
259 uint8_t *data, Tick delay, Request::Flags flag)
260{
261 assert(device->getState() == SimObject::Running);
262
263 DmaReqState *reqState = new DmaReqState(event, this, size, delay);
264
265
266 DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
267 event ? event->scheduled() : -1 );
268 for (ChunkGenerator gen(addr, size, peerBlockSize());
269 !gen.done(); gen.next()) {
270 Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
271 PacketPtr pkt = new Packet(req, cmd);
272
273 // Increment the data pointer on a write
274 if (data)
275 pkt->dataStatic(data + gen.complete());
276
277 pkt->senderState = reqState;
278
279 assert(pendingCount >= 0);
280 pendingCount++;
281 DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
282 gen.size());
283 queueDma(pkt);
284 }
285
286}
287
288void
289DmaPort::queueDma(PacketPtr pkt, bool front)
290{
291
292 if (front)
293 transmitList.push_front(pkt);
294 else
295 transmitList.push_back(pkt);
296 sendDma();
297}
298
299
300void
301DmaPort::sendDma()
302{
303 // some kind of selction between access methods
304 // more work is going to have to be done to make
305 // switching actually work
306 assert(transmitList.size());
307 PacketPtr pkt = transmitList.front();
308
309 Enums::MemoryMode state = sys->getMemoryMode();
310 if (state == Enums::timing) {
311 if (backoffEvent.scheduled() || inRetry) {
312 DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n");
313 return;
314 }
315
316 DPRINTF(DMA, "Attempting to send %s addr %#x\n",
317 pkt->cmdString(), pkt->getAddr());
318
319 bool result;
320 do {
321 result = sendTimingReq(pkt);
322 if (result) {
323 transmitList.pop_front();
324 DPRINTF(DMA, "-- Done\n");
325 } else {
326 inRetry = true;
327 DPRINTF(DMA, "-- Failed: queued\n");
328 }
329 } while (result && !backoffTime && transmitList.size());
330
331 if (transmitList.size() && backoffTime && !inRetry &&
332 !backoffEvent.scheduled()) {
333 DPRINTF(DMA, "-- Scheduling backoff timer for %d\n",
334 backoffTime+curTick());
335 device->schedule(backoffEvent, backoffTime + curTick());
336 }
337 } else if (state == Enums::atomic) {
338 transmitList.pop_front();
339
340 Tick lat;
341 DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n",
342 pkt->req->getPaddr(), pkt->req->getSize());
343 lat = sendAtomic(pkt);
344 assert(pkt->senderState);
345 DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
346 assert(state);
347 state->numBytes += pkt->req->getSize();
348
349 DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n",
350 pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes,
351 state->totBytes,
352 state->completionEvent ? state->completionEvent->scheduled() : 0 );
353
354 if (state->totBytes == state->numBytes) {
355 if (state->completionEvent) {
356 assert(!state->completionEvent->scheduled());
357 device->schedule(state->completionEvent,
358 curTick() + lat + state->delay);
359 }
360 delete state;
361 delete pkt->req;
362 }
363 pendingCount--;
364 assert(pendingCount >= 0);
365 delete pkt;
366
367 if (pendingCount == 0 && drainEvent) {
368 drainEvent->process();
369 drainEvent = NULL;
370 }
371
372 } else
373 panic("Unknown memory command state.");
374}
375
376DmaDevice::~DmaDevice()
377{
378}
379
380
381MasterPort &
382DmaDevice::getMasterPort(const std::string &if_name, int idx)
383{
384 if (if_name == "dma") {
385 return dmaPort;
386 }
387 return PioDevice::getMasterPort(if_name, idx);
388}
389