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