arm: Remove the 'magic MSI register' in the GIC (PL390)
[gem5.git] / src / dev / copy_engine.cc
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) 2008 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 */
42
43 /* @file
44 * Device model for Intel's I/O AT DMA copy engine.
45 */
46
47 #include <algorithm>
48
49 #include "base/cp_annotate.hh"
50 #include "base/trace.hh"
51 #include "debug/DMACopyEngine.hh"
52 #include "debug/Drain.hh"
53 #include "dev/copy_engine.hh"
54 #include "mem/packet.hh"
55 #include "mem/packet_access.hh"
56 #include "params/CopyEngine.hh"
57 #include "sim/stats.hh"
58 #include "sim/system.hh"
59
60 using namespace CopyEngineReg;
61
62 CopyEngine::CopyEngine(const Params *p)
63 : PciDevice(p)
64 {
65 // All Reg regs are initialized to 0 by default
66 regs.chanCount = p->ChanCnt;
67 regs.xferCap = findMsbSet(p->XferCap);
68 regs.attnStatus = 0;
69
70 if (regs.chanCount > 64)
71 fatal("CopyEngine interface doesn't support more than 64 DMA engines\n");
72
73 for (int x = 0; x < regs.chanCount; x++) {
74 CopyEngineChannel *ch = new CopyEngineChannel(this, x);
75 chan.push_back(ch);
76 }
77 }
78
79
80 CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
81 : cePort(_ce, _ce->sys),
82 ce(_ce), channelId(cid), busy(false), underReset(false),
83 refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
84 latAfterCompletion(ce->params()->latAfterCompletion),
85 completionDataReg(0), nextState(Idle), drainManager(NULL),
86 fetchCompleteEvent(this), addrCompleteEvent(this),
87 readCompleteEvent(this), writeCompleteEvent(this),
88 statusCompleteEvent(this)
89
90 {
91 cr.status.dma_transfer_status(3);
92 cr.descChainAddr = 0;
93 cr.completionAddr = 0;
94
95 curDmaDesc = new DmaDesc;
96 memset(curDmaDesc, 0, sizeof(DmaDesc));
97 copyBuffer = new uint8_t[ce->params()->XferCap];
98 }
99
100 CopyEngine::~CopyEngine()
101 {
102 for (int x = 0; x < chan.size(); x++) {
103 delete chan[x];
104 }
105 }
106
107 CopyEngine::CopyEngineChannel::~CopyEngineChannel()
108 {
109 delete curDmaDesc;
110 delete [] copyBuffer;
111 }
112
113 BaseMasterPort &
114 CopyEngine::getMasterPort(const std::string &if_name, PortID idx)
115 {
116 if (if_name != "dma") {
117 // pass it along to our super class
118 return PciDevice::getMasterPort(if_name, idx);
119 } else {
120 if (idx >= static_cast<int>(chan.size())) {
121 panic("CopyEngine::getMasterPort: unknown index %d\n", idx);
122 }
123
124 return chan[idx]->getMasterPort();
125 }
126 }
127
128
129 BaseMasterPort &
130 CopyEngine::CopyEngineChannel::getMasterPort()
131 {
132 return cePort;
133 }
134
135 void
136 CopyEngine::CopyEngineChannel::recvCommand()
137 {
138 if (cr.command.start_dma()) {
139 assert(!busy);
140 cr.status.dma_transfer_status(0);
141 nextState = DescriptorFetch;
142 fetchAddress = cr.descChainAddr;
143 if (ce->getDrainState() == Drainable::Running)
144 fetchDescriptor(cr.descChainAddr);
145 } else if (cr.command.append_dma()) {
146 if (!busy) {
147 nextState = AddressFetch;
148 if (ce->getDrainState() == Drainable::Running)
149 fetchNextAddr(lastDescriptorAddr);
150 } else
151 refreshNext = true;
152 } else if (cr.command.reset_dma()) {
153 if (busy)
154 underReset = true;
155 else {
156 cr.status.dma_transfer_status(3);
157 nextState = Idle;
158 }
159 } else if (cr.command.resume_dma() || cr.command.abort_dma() ||
160 cr.command.suspend_dma())
161 panic("Resume, Abort, and Suspend are not supported\n");
162 cr.command(0);
163 }
164
165 Tick
166 CopyEngine::read(PacketPtr pkt)
167 {
168 int bar;
169 Addr daddr;
170
171 if (!getBAR(pkt->getAddr(), bar, daddr))
172 panic("Invalid PCI memory access to unmapped memory.\n");
173
174 // Only Memory register BAR is allowed
175 assert(bar == 0);
176
177 int size = pkt->getSize();
178 if (size != sizeof(uint64_t) && size != sizeof(uint32_t) &&
179 size != sizeof(uint16_t) && size != sizeof(uint8_t)) {
180 panic("Unknown size for MMIO access: %d\n", pkt->getSize());
181 }
182
183 DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size);
184
185 ///
186 /// Handle read of register here
187 ///
188
189 if (daddr < 0x80) {
190 switch (daddr) {
191 case GEN_CHANCOUNT:
192 assert(size == sizeof(regs.chanCount));
193 pkt->set<uint8_t>(regs.chanCount);
194 break;
195 case GEN_XFERCAP:
196 assert(size == sizeof(regs.xferCap));
197 pkt->set<uint8_t>(regs.xferCap);
198 break;
199 case GEN_INTRCTRL:
200 assert(size == sizeof(uint8_t));
201 pkt->set<uint8_t>(regs.intrctrl());
202 regs.intrctrl.master_int_enable(0);
203 break;
204 case GEN_ATTNSTATUS:
205 assert(size == sizeof(regs.attnStatus));
206 pkt->set<uint32_t>(regs.attnStatus);
207 regs.attnStatus = 0;
208 break;
209 default:
210 panic("Read request to unknown register number: %#x\n", daddr);
211 }
212 pkt->makeAtomicResponse();
213 return pioDelay;
214 }
215
216
217 // Find which channel we're accessing
218 int chanid = 0;
219 daddr -= 0x80;
220 while (daddr >= 0x80) {
221 chanid++;
222 daddr -= 0x80;
223 }
224
225 if (chanid >= regs.chanCount)
226 panic("Access to channel %d (device only configured for %d channels)",
227 chanid, regs.chanCount);
228
229 ///
230 /// Channel registers are handled here
231 ///
232 chan[chanid]->channelRead(pkt, daddr, size);
233
234 pkt->makeAtomicResponse();
235 return pioDelay;
236 }
237
238 void
239 CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size)
240 {
241 switch (daddr) {
242 case CHAN_CONTROL:
243 assert(size == sizeof(uint16_t));
244 pkt->set<uint16_t>(cr.ctrl());
245 cr.ctrl.in_use(1);
246 break;
247 case CHAN_STATUS:
248 assert(size == sizeof(uint64_t));
249 pkt->set<uint64_t>(cr.status() | ~busy);
250 break;
251 case CHAN_CHAINADDR:
252 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
253 if (size == sizeof(uint64_t))
254 pkt->set<uint64_t>(cr.descChainAddr);
255 else
256 pkt->set<uint32_t>(bits(cr.descChainAddr,0,31));
257 break;
258 case CHAN_CHAINADDR_HIGH:
259 assert(size == sizeof(uint32_t));
260 pkt->set<uint32_t>(bits(cr.descChainAddr,32,63));
261 break;
262 case CHAN_COMMAND:
263 assert(size == sizeof(uint8_t));
264 pkt->set<uint32_t>(cr.command());
265 break;
266 case CHAN_CMPLNADDR:
267 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
268 if (size == sizeof(uint64_t))
269 pkt->set<uint64_t>(cr.completionAddr);
270 else
271 pkt->set<uint32_t>(bits(cr.completionAddr,0,31));
272 break;
273 case CHAN_CMPLNADDR_HIGH:
274 assert(size == sizeof(uint32_t));
275 pkt->set<uint32_t>(bits(cr.completionAddr,32,63));
276 break;
277 case CHAN_ERROR:
278 assert(size == sizeof(uint32_t));
279 pkt->set<uint32_t>(cr.error());
280 break;
281 default:
282 panic("Read request to unknown channel register number: (%d)%#x\n",
283 channelId, daddr);
284 }
285 }
286
287
288 Tick
289 CopyEngine::write(PacketPtr pkt)
290 {
291 int bar;
292 Addr daddr;
293
294
295 if (!getBAR(pkt->getAddr(), bar, daddr))
296 panic("Invalid PCI memory access to unmapped memory.\n");
297
298 // Only Memory register BAR is allowed
299 assert(bar == 0);
300
301 int size = pkt->getSize();
302
303 ///
304 /// Handle write of register here
305 ///
306
307 if (size == sizeof(uint64_t)) {
308 uint64_t val M5_VAR_USED = pkt->get<uint64_t>();
309 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
310 } else if (size == sizeof(uint32_t)) {
311 uint32_t val M5_VAR_USED = pkt->get<uint32_t>();
312 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
313 } else if (size == sizeof(uint16_t)) {
314 uint16_t val M5_VAR_USED = pkt->get<uint16_t>();
315 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
316 } else if (size == sizeof(uint8_t)) {
317 uint8_t val M5_VAR_USED = pkt->get<uint8_t>();
318 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
319 } else {
320 panic("Unknown size for MMIO access: %d\n", size);
321 }
322
323 if (daddr < 0x80) {
324 switch (daddr) {
325 case GEN_CHANCOUNT:
326 case GEN_XFERCAP:
327 case GEN_ATTNSTATUS:
328 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
329 daddr);
330 break;
331 case GEN_INTRCTRL:
332 regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1));
333 break;
334 default:
335 panic("Read request to unknown register number: %#x\n", daddr);
336 }
337 pkt->makeAtomicResponse();
338 return pioDelay;
339 }
340
341 // Find which channel we're accessing
342 int chanid = 0;
343 daddr -= 0x80;
344 while (daddr >= 0x80) {
345 chanid++;
346 daddr -= 0x80;
347 }
348
349 if (chanid >= regs.chanCount)
350 panic("Access to channel %d (device only configured for %d channels)",
351 chanid, regs.chanCount);
352
353 ///
354 /// Channel registers are handled here
355 ///
356 chan[chanid]->channelWrite(pkt, daddr, size);
357
358 pkt->makeAtomicResponse();
359 return pioDelay;
360 }
361
362 void
363 CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size)
364 {
365 switch (daddr) {
366 case CHAN_CONTROL:
367 assert(size == sizeof(uint16_t));
368 int old_int_disable;
369 old_int_disable = cr.ctrl.interrupt_disable();
370 cr.ctrl(pkt->get<uint16_t>());
371 if (cr.ctrl.interrupt_disable())
372 cr.ctrl.interrupt_disable(0);
373 else
374 cr.ctrl.interrupt_disable(old_int_disable);
375 break;
376 case CHAN_STATUS:
377 assert(size == sizeof(uint64_t));
378 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
379 daddr);
380 break;
381 case CHAN_CHAINADDR:
382 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
383 if (size == sizeof(uint64_t))
384 cr.descChainAddr = pkt->get<uint64_t>();
385 else
386 cr.descChainAddr = (uint64_t)pkt->get<uint32_t>() |
387 (cr.descChainAddr & ~mask(32));
388 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
389 break;
390 case CHAN_CHAINADDR_HIGH:
391 assert(size == sizeof(uint32_t));
392 cr.descChainAddr = ((uint64_t)pkt->get<uint32_t>() <<32) |
393 (cr.descChainAddr & mask(32));
394 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
395 break;
396 case CHAN_COMMAND:
397 assert(size == sizeof(uint8_t));
398 cr.command(pkt->get<uint8_t>());
399 recvCommand();
400 break;
401 case CHAN_CMPLNADDR:
402 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
403 if (size == sizeof(uint64_t))
404 cr.completionAddr = pkt->get<uint64_t>();
405 else
406 cr.completionAddr = pkt->get<uint32_t>() |
407 (cr.completionAddr & ~mask(32));
408 break;
409 case CHAN_CMPLNADDR_HIGH:
410 assert(size == sizeof(uint32_t));
411 cr.completionAddr = ((uint64_t)pkt->get<uint32_t>() <<32) |
412 (cr.completionAddr & mask(32));
413 break;
414 case CHAN_ERROR:
415 assert(size == sizeof(uint32_t));
416 cr.error(~pkt->get<uint32_t>() & cr.error());
417 break;
418 default:
419 panic("Read request to unknown channel register number: (%d)%#x\n",
420 channelId, daddr);
421 }
422 }
423
424 void
425 CopyEngine::regStats()
426 {
427 using namespace Stats;
428 bytesCopied
429 .init(regs.chanCount)
430 .name(name() + ".bytes_copied")
431 .desc("Number of bytes copied by each engine")
432 .flags(total)
433 ;
434 copiesProcessed
435 .init(regs.chanCount)
436 .name(name() + ".copies_processed")
437 .desc("Number of copies processed by each engine")
438 .flags(total)
439 ;
440 }
441
442 void
443 CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address)
444 {
445 anDq();
446 anBegin("FetchDescriptor");
447 DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n",
448 address, ce->platform->pciToDma(address));
449 assert(address);
450 busy = true;
451
452 DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n",
453 ce->platform->pciToDma(address), sizeof(DmaDesc), curDmaDesc);
454
455 cePort.dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address),
456 sizeof(DmaDesc), &fetchCompleteEvent,
457 (uint8_t*)curDmaDesc, latBeforeBegin);
458 lastDescriptorAddr = address;
459 }
460
461 void
462 CopyEngine::CopyEngineChannel::fetchDescComplete()
463 {
464 DPRINTF(DMACopyEngine, "Read of descriptor complete\n");
465
466 if ((curDmaDesc->command & DESC_CTRL_NULL)) {
467 DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n");
468 assert(!(curDmaDesc->command & DESC_CTRL_CP_STS));
469 if (curDmaDesc->command & DESC_CTRL_CP_STS) {
470 panic("Shouldn't be able to get here\n");
471 nextState = CompletionWrite;
472 if (inDrain()) return;
473 writeCompletionStatus();
474 } else {
475 anBegin("Idle");
476 anWait();
477 busy = false;
478 nextState = Idle;
479 inDrain();
480 }
481 return;
482 }
483
484 if (curDmaDesc->command & ~DESC_CTRL_CP_STS)
485 panic("Descriptor has flag other that completion status set\n");
486
487 nextState = DMARead;
488 if (inDrain()) return;
489 readCopyBytes();
490 }
491
492 void
493 CopyEngine::CopyEngineChannel::readCopyBytes()
494 {
495 anBegin("ReadCopyBytes");
496 DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n",
497 curDmaDesc->len, curDmaDesc->dest,
498 ce->platform->pciToDma(curDmaDesc->src));
499 cePort.dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(curDmaDesc->src),
500 curDmaDesc->len, &readCompleteEvent, copyBuffer, 0);
501 }
502
503 void
504 CopyEngine::CopyEngineChannel::readCopyBytesComplete()
505 {
506 DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n");
507
508 nextState = DMAWrite;
509 if (inDrain()) return;
510 writeCopyBytes();
511 }
512
513 void
514 CopyEngine::CopyEngineChannel::writeCopyBytes()
515 {
516 anBegin("WriteCopyBytes");
517 DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n",
518 curDmaDesc->len, curDmaDesc->dest,
519 ce->platform->pciToDma(curDmaDesc->dest));
520
521 cePort.dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(curDmaDesc->dest),
522 curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0);
523
524 ce->bytesCopied[channelId] += curDmaDesc->len;
525 ce->copiesProcessed[channelId]++;
526 }
527
528 void
529 CopyEngine::CopyEngineChannel::writeCopyBytesComplete()
530 {
531 DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n",
532 curDmaDesc->user1);
533
534 cr.status.compl_desc_addr(lastDescriptorAddr >> 6);
535 completionDataReg = cr.status() | 1;
536
537 anQ("DMAUsedDescQ", channelId, 1);
538 anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len);
539 if (curDmaDesc->command & DESC_CTRL_CP_STS) {
540 nextState = CompletionWrite;
541 if (inDrain()) return;
542 writeCompletionStatus();
543 return;
544 }
545
546 continueProcessing();
547 }
548
549 void
550 CopyEngine::CopyEngineChannel::continueProcessing()
551 {
552 busy = false;
553
554 if (underReset) {
555 anBegin("Reset");
556 anWait();
557 underReset = false;
558 refreshNext = false;
559 busy = false;
560 nextState = Idle;
561 return;
562 }
563
564 if (curDmaDesc->next) {
565 nextState = DescriptorFetch;
566 fetchAddress = curDmaDesc->next;
567 if (inDrain()) return;
568 fetchDescriptor(curDmaDesc->next);
569 } else if (refreshNext) {
570 nextState = AddressFetch;
571 refreshNext = false;
572 if (inDrain()) return;
573 fetchNextAddr(lastDescriptorAddr);
574 } else {
575 inDrain();
576 nextState = Idle;
577 anWait();
578 anBegin("Idle");
579 }
580 }
581
582 void
583 CopyEngine::CopyEngineChannel::writeCompletionStatus()
584 {
585 anBegin("WriteCompletionStatus");
586 DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n",
587 completionDataReg, cr.completionAddr,
588 ce->platform->pciToDma(cr.completionAddr));
589
590 cePort.dmaAction(MemCmd::WriteReq,
591 ce->platform->pciToDma(cr.completionAddr),
592 sizeof(completionDataReg), &statusCompleteEvent,
593 (uint8_t*)&completionDataReg, latAfterCompletion);
594 }
595
596 void
597 CopyEngine::CopyEngineChannel::writeStatusComplete()
598 {
599 DPRINTF(DMACopyEngine, "Writing completion status complete\n");
600 continueProcessing();
601 }
602
603 void
604 CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address)
605 {
606 anBegin("FetchNextAddr");
607 DPRINTF(DMACopyEngine, "Fetching next address...\n");
608 busy = true;
609 cePort.dmaAction(MemCmd::ReadReq,
610 ce->platform->pciToDma(address + offsetof(DmaDesc, next)),
611 sizeof(Addr), &addrCompleteEvent,
612 (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0);
613 }
614
615 void
616 CopyEngine::CopyEngineChannel::fetchAddrComplete()
617 {
618 DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n",
619 curDmaDesc->next);
620 if (!curDmaDesc->next) {
621 DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n");
622 busy = false;
623 nextState = Idle;
624 anWait();
625 anBegin("Idle");
626 inDrain();
627 return;
628 }
629 nextState = DescriptorFetch;
630 fetchAddress = curDmaDesc->next;
631 if (inDrain()) return;
632 fetchDescriptor(curDmaDesc->next);
633 }
634
635 bool
636 CopyEngine::CopyEngineChannel::inDrain()
637 {
638 if (ce->getDrainState() == Drainable::Draining) {
639 DPRINTF(Drain, "CopyEngine done draining, processing drain event\n");
640 assert(drainManager);
641 drainManager->signalDrainDone();
642 drainManager = NULL;
643 }
644
645 return ce->getDrainState() != Drainable::Running;
646 }
647
648 unsigned int
649 CopyEngine::CopyEngineChannel::drain(DrainManager *dm)
650 {
651 if (nextState == Idle || ce->getDrainState() != Drainable::Running)
652 return 0;
653 unsigned int count = 1;
654 count += cePort.drain(dm);
655
656 DPRINTF(Drain, "CopyEngineChannel not drained\n");
657 this->drainManager = dm;
658 return count;
659 }
660
661 unsigned int
662 CopyEngine::drain(DrainManager *dm)
663 {
664 unsigned int count;
665 count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
666 for (int x = 0;x < chan.size(); x++)
667 count += chan[x]->drain(dm);
668
669 if (count)
670 setDrainState(Draining);
671 else
672 setDrainState(Drained);
673
674 DPRINTF(Drain, "CopyEngine not drained\n");
675 return count;
676 }
677
678 void
679 CopyEngine::serialize(std::ostream &os)
680 {
681 PciDevice::serialize(os);
682 regs.serialize(os);
683 for (int x =0; x < chan.size(); x++) {
684 nameOut(os, csprintf("%s.channel%d", name(), x));
685 chan[x]->serialize(os);
686 }
687 }
688
689 void
690 CopyEngine::unserialize(Checkpoint *cp, const std::string &section)
691 {
692 PciDevice::unserialize(cp, section);
693 regs.unserialize(cp, section);
694 for (int x = 0; x < chan.size(); x++)
695 chan[x]->unserialize(cp, csprintf("%s.channel%d", section, x));
696 }
697
698 void
699 CopyEngine::CopyEngineChannel::serialize(std::ostream &os)
700 {
701 SERIALIZE_SCALAR(channelId);
702 SERIALIZE_SCALAR(busy);
703 SERIALIZE_SCALAR(underReset);
704 SERIALIZE_SCALAR(refreshNext);
705 SERIALIZE_SCALAR(lastDescriptorAddr);
706 SERIALIZE_SCALAR(completionDataReg);
707 SERIALIZE_SCALAR(fetchAddress);
708 int nextState = this->nextState;
709 SERIALIZE_SCALAR(nextState);
710 arrayParamOut(os, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
711 SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
712 cr.serialize(os);
713
714 }
715 void
716 CopyEngine::CopyEngineChannel::unserialize(Checkpoint *cp, const std::string &section)
717 {
718 UNSERIALIZE_SCALAR(channelId);
719 UNSERIALIZE_SCALAR(busy);
720 UNSERIALIZE_SCALAR(underReset);
721 UNSERIALIZE_SCALAR(refreshNext);
722 UNSERIALIZE_SCALAR(lastDescriptorAddr);
723 UNSERIALIZE_SCALAR(completionDataReg);
724 UNSERIALIZE_SCALAR(fetchAddress);
725 int nextState;
726 UNSERIALIZE_SCALAR(nextState);
727 this->nextState = (ChannelState)nextState;
728 arrayParamIn(cp, section, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
729 UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
730 cr.unserialize(cp, section);
731
732 }
733
734 void
735 CopyEngine::CopyEngineChannel::restartStateMachine()
736 {
737 switch(nextState) {
738 case AddressFetch:
739 fetchNextAddr(lastDescriptorAddr);
740 break;
741 case DescriptorFetch:
742 fetchDescriptor(fetchAddress);
743 break;
744 case DMARead:
745 readCopyBytes();
746 break;
747 case DMAWrite:
748 writeCopyBytes();
749 break;
750 case CompletionWrite:
751 writeCompletionStatus();
752 break;
753 case Idle:
754 break;
755 default:
756 panic("Unknown state for CopyEngineChannel\n");
757 }
758 }
759
760 void
761 CopyEngine::drainResume()
762 {
763 Drainable::drainResume();
764 for (int x = 0;x < chan.size(); x++)
765 chan[x]->drainResume();
766 }
767
768
769 void
770 CopyEngine::CopyEngineChannel::drainResume()
771 {
772 DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
773 restartStateMachine();
774 }
775
776 CopyEngine *
777 CopyEngineParams::create()
778 {
779 return new CopyEngine(this);
780 }