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