misc: Updated the RELEASE-NOTES and version number
[gem5.git] / src / dev / pci / 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
41 /* @file
42 * Device model for Intel's I/O AT DMA copy engine.
43 */
44
45 #include "dev/pci/copy_engine.hh"
46
47 #include <algorithm>
48
49 #include "base/trace.hh"
50 #include "debug/DMACopyEngine.hh"
51 #include "debug/Drain.hh"
52 #include "mem/packet.hh"
53 #include "mem/packet_access.hh"
54 #include "params/CopyEngine.hh"
55 #include "sim/stats.hh"
56 #include "sim/system.hh"
57
58 using namespace CopyEngineReg;
59
60 CopyEngine::CopyEngine(const Params *p)
61 : PciDevice(p)
62 {
63 // All Reg regs are initialized to 0 by default
64 regs.chanCount = p->ChanCnt;
65 regs.xferCap = findMsbSet(p->XferCap);
66 regs.attnStatus = 0;
67
68 if (regs.chanCount > 64)
69 fatal("CopyEngine interface doesn't support more than 64 DMA engines\n");
70
71 for (int x = 0; x < regs.chanCount; x++) {
72 CopyEngineChannel *ch = new CopyEngineChannel(this, x);
73 chan.push_back(ch);
74 }
75 }
76
77
78 CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
79 : cePort(_ce, _ce->sys),
80 ce(_ce), channelId(cid), busy(false), underReset(false),
81 refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
82 latAfterCompletion(ce->params()->latAfterCompletion),
83 completionDataReg(0), nextState(Idle),
84 fetchCompleteEvent([this]{ fetchDescComplete(); }, name()),
85 addrCompleteEvent([this]{ fetchAddrComplete(); }, name()),
86 readCompleteEvent([this]{ readCopyBytesComplete(); }, name()),
87 writeCompleteEvent([this]{ writeCopyBytesComplete(); }, name()),
88 statusCompleteEvent([this]{ writeStatusComplete(); }, name())
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 Port &
114 CopyEngine::getPort(const std::string &if_name, PortID idx)
115 {
116 if (if_name != "dma") {
117 // pass it along to our super class
118 return PciDevice::getPort(if_name, idx);
119 } else {
120 if (idx >= static_cast<int>(chan.size())) {
121 panic("CopyEngine::getPort: unknown index %d\n", idx);
122 }
123
124 return chan[idx]->getPort();
125 }
126 }
127
128
129 Port &
130 CopyEngine::CopyEngineChannel::getPort()
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->drainState() == DrainState::Running)
144 fetchDescriptor(cr.descChainAddr);
145 } else if (cr.command.append_dma()) {
146 if (!busy) {
147 nextState = AddressFetch;
148 if (ce->drainState() == DrainState::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->setLE<uint8_t>(regs.chanCount);
194 break;
195 case GEN_XFERCAP:
196 assert(size == sizeof(regs.xferCap));
197 pkt->setLE<uint8_t>(regs.xferCap);
198 break;
199 case GEN_INTRCTRL:
200 assert(size == sizeof(uint8_t));
201 pkt->setLE<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->setLE<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->setLE<uint16_t>(cr.ctrl());
245 cr.ctrl.in_use(1);
246 break;
247 case CHAN_STATUS:
248 assert(size == sizeof(uint64_t));
249 pkt->setLE<uint64_t>(cr.status() | (busy ? 0 : 1));
250 break;
251 case CHAN_CHAINADDR:
252 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
253 if (size == sizeof(uint64_t))
254 pkt->setLE<uint64_t>(cr.descChainAddr);
255 else
256 pkt->setLE<uint32_t>(bits(cr.descChainAddr,0,31));
257 break;
258 case CHAN_CHAINADDR_HIGH:
259 assert(size == sizeof(uint32_t));
260 pkt->setLE<uint32_t>(bits(cr.descChainAddr,32,63));
261 break;
262 case CHAN_COMMAND:
263 assert(size == sizeof(uint8_t));
264 pkt->setLE<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->setLE<uint64_t>(cr.completionAddr);
270 else
271 pkt->setLE<uint32_t>(bits(cr.completionAddr,0,31));
272 break;
273 case CHAN_CMPLNADDR_HIGH:
274 assert(size == sizeof(uint32_t));
275 pkt->setLE<uint32_t>(bits(cr.completionAddr,32,63));
276 break;
277 case CHAN_ERROR:
278 assert(size == sizeof(uint32_t));
279 pkt->setLE<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->getLE<uint64_t>();
309 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n",
310 daddr, val);
311 } else if (size == sizeof(uint32_t)) {
312 uint32_t val M5_VAR_USED = pkt->getLE<uint32_t>();
313 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n",
314 daddr, val);
315 } else if (size == sizeof(uint16_t)) {
316 uint16_t val M5_VAR_USED = pkt->getLE<uint16_t>();
317 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n",
318 daddr, val);
319 } else if (size == sizeof(uint8_t)) {
320 uint8_t val M5_VAR_USED = pkt->getLE<uint8_t>();
321 DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n",
322 daddr, val);
323 } else {
324 panic("Unknown size for MMIO access: %d\n", size);
325 }
326
327 if (daddr < 0x80) {
328 switch (daddr) {
329 case GEN_CHANCOUNT:
330 case GEN_XFERCAP:
331 case GEN_ATTNSTATUS:
332 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
333 daddr);
334 break;
335 case GEN_INTRCTRL:
336 regs.intrctrl.master_int_enable(bits(pkt->getLE<uint8_t>(), 0, 1));
337 break;
338 default:
339 panic("Read request to unknown register number: %#x\n", daddr);
340 }
341 pkt->makeAtomicResponse();
342 return pioDelay;
343 }
344
345 // Find which channel we're accessing
346 int chanid = 0;
347 daddr -= 0x80;
348 while (daddr >= 0x80) {
349 chanid++;
350 daddr -= 0x80;
351 }
352
353 if (chanid >= regs.chanCount)
354 panic("Access to channel %d (device only configured for %d channels)",
355 chanid, regs.chanCount);
356
357 ///
358 /// Channel registers are handled here
359 ///
360 chan[chanid]->channelWrite(pkt, daddr, size);
361
362 pkt->makeAtomicResponse();
363 return pioDelay;
364 }
365
366 void
367 CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size)
368 {
369 switch (daddr) {
370 case CHAN_CONTROL:
371 assert(size == sizeof(uint16_t));
372 int old_int_disable;
373 old_int_disable = cr.ctrl.interrupt_disable();
374 cr.ctrl(pkt->getLE<uint16_t>());
375 if (cr.ctrl.interrupt_disable())
376 cr.ctrl.interrupt_disable(0);
377 else
378 cr.ctrl.interrupt_disable(old_int_disable);
379 break;
380 case CHAN_STATUS:
381 assert(size == sizeof(uint64_t));
382 DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
383 daddr);
384 break;
385 case CHAN_CHAINADDR:
386 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
387 if (size == sizeof(uint64_t))
388 cr.descChainAddr = pkt->getLE<uint64_t>();
389 else
390 cr.descChainAddr = (uint64_t)pkt->getLE<uint32_t>() |
391 (cr.descChainAddr & ~mask(32));
392 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
393 break;
394 case CHAN_CHAINADDR_HIGH:
395 assert(size == sizeof(uint32_t));
396 cr.descChainAddr = ((uint64_t)pkt->getLE<uint32_t>() << 32) |
397 (cr.descChainAddr & mask(32));
398 DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
399 break;
400 case CHAN_COMMAND:
401 assert(size == sizeof(uint8_t));
402 cr.command(pkt->getLE<uint8_t>());
403 recvCommand();
404 break;
405 case CHAN_CMPLNADDR:
406 assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
407 if (size == sizeof(uint64_t))
408 cr.completionAddr = pkt->getLE<uint64_t>();
409 else
410 cr.completionAddr = pkt->getLE<uint32_t>() |
411 (cr.completionAddr & ~mask(32));
412 break;
413 case CHAN_CMPLNADDR_HIGH:
414 assert(size == sizeof(uint32_t));
415 cr.completionAddr = ((uint64_t)pkt->getLE<uint32_t>() <<32) |
416 (cr.completionAddr & mask(32));
417 break;
418 case CHAN_ERROR:
419 assert(size == sizeof(uint32_t));
420 cr.error(~pkt->getLE<uint32_t>() & cr.error());
421 break;
422 default:
423 panic("Read request to unknown channel register number: (%d)%#x\n",
424 channelId, daddr);
425 }
426 }
427
428 void
429 CopyEngine::regStats()
430 {
431 PciDevice::regStats();
432
433 using namespace Stats;
434 bytesCopied
435 .init(regs.chanCount)
436 .name(name() + ".bytes_copied")
437 .desc("Number of bytes copied by each engine")
438 .flags(total)
439 ;
440 copiesProcessed
441 .init(regs.chanCount)
442 .name(name() + ".copies_processed")
443 .desc("Number of copies processed by each engine")
444 .flags(total)
445 ;
446 }
447
448 void
449 CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address)
450 {
451 DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n",
452 address, ce->pciToDma(address));
453 assert(address);
454 busy = true;
455
456 DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n",
457 ce->pciToDma(address), sizeof(DmaDesc), curDmaDesc);
458
459 cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(address),
460 sizeof(DmaDesc), &fetchCompleteEvent,
461 (uint8_t*)curDmaDesc, latBeforeBegin);
462 lastDescriptorAddr = address;
463 }
464
465 void
466 CopyEngine::CopyEngineChannel::fetchDescComplete()
467 {
468 DPRINTF(DMACopyEngine, "Read of descriptor complete\n");
469
470 if ((curDmaDesc->command & DESC_CTRL_NULL)) {
471 DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n");
472 assert(!(curDmaDesc->command & DESC_CTRL_CP_STS));
473 if (curDmaDesc->command & DESC_CTRL_CP_STS) {
474 panic("Shouldn't be able to get here\n");
475 nextState = CompletionWrite;
476 if (inDrain()) return;
477 writeCompletionStatus();
478 } else {
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 DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n",
498 curDmaDesc->len, curDmaDesc->dest,
499 ce->pciToDma(curDmaDesc->src));
500 cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(curDmaDesc->src),
501 curDmaDesc->len, &readCompleteEvent, copyBuffer, 0);
502 }
503
504 void
505 CopyEngine::CopyEngineChannel::readCopyBytesComplete()
506 {
507 DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n");
508
509 nextState = DMAWrite;
510 if (inDrain()) return;
511 writeCopyBytes();
512 }
513
514 void
515 CopyEngine::CopyEngineChannel::writeCopyBytes()
516 {
517 DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n",
518 curDmaDesc->len, curDmaDesc->dest,
519 ce->pciToDma(curDmaDesc->dest));
520
521 cePort.dmaAction(MemCmd::WriteReq, ce->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 if (curDmaDesc->command & DESC_CTRL_CP_STS) {
538 nextState = CompletionWrite;
539 if (inDrain()) return;
540 writeCompletionStatus();
541 return;
542 }
543
544 continueProcessing();
545 }
546
547 void
548 CopyEngine::CopyEngineChannel::continueProcessing()
549 {
550 busy = false;
551
552 if (underReset) {
553 underReset = false;
554 refreshNext = false;
555 busy = false;
556 nextState = Idle;
557 return;
558 }
559
560 if (curDmaDesc->next) {
561 nextState = DescriptorFetch;
562 fetchAddress = curDmaDesc->next;
563 if (inDrain()) return;
564 fetchDescriptor(curDmaDesc->next);
565 } else if (refreshNext) {
566 nextState = AddressFetch;
567 refreshNext = false;
568 if (inDrain()) return;
569 fetchNextAddr(lastDescriptorAddr);
570 } else {
571 inDrain();
572 nextState = Idle;
573 }
574 }
575
576 void
577 CopyEngine::CopyEngineChannel::writeCompletionStatus()
578 {
579 DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n",
580 completionDataReg, cr.completionAddr,
581 ce->pciToDma(cr.completionAddr));
582
583 cePort.dmaAction(MemCmd::WriteReq,
584 ce->pciToDma(cr.completionAddr),
585 sizeof(completionDataReg), &statusCompleteEvent,
586 (uint8_t*)&completionDataReg, latAfterCompletion);
587 }
588
589 void
590 CopyEngine::CopyEngineChannel::writeStatusComplete()
591 {
592 DPRINTF(DMACopyEngine, "Writing completion status complete\n");
593 continueProcessing();
594 }
595
596 void
597 CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address)
598 {
599 DPRINTF(DMACopyEngine, "Fetching next address...\n");
600 busy = true;
601 cePort.dmaAction(MemCmd::ReadReq,
602 ce->pciToDma(address + offsetof(DmaDesc, next)),
603 sizeof(Addr), &addrCompleteEvent,
604 (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0);
605 }
606
607 void
608 CopyEngine::CopyEngineChannel::fetchAddrComplete()
609 {
610 DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n",
611 curDmaDesc->next);
612 if (!curDmaDesc->next) {
613 DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n");
614 busy = false;
615 nextState = Idle;
616 inDrain();
617 return;
618 }
619 nextState = DescriptorFetch;
620 fetchAddress = curDmaDesc->next;
621 if (inDrain()) return;
622 fetchDescriptor(curDmaDesc->next);
623 }
624
625 bool
626 CopyEngine::CopyEngineChannel::inDrain()
627 {
628 if (drainState() == DrainState::Draining) {
629 DPRINTF(Drain, "CopyEngine done draining, processing drain event\n");
630 signalDrainDone();
631 }
632
633 return ce->drainState() != DrainState::Running;
634 }
635
636 DrainState
637 CopyEngine::CopyEngineChannel::drain()
638 {
639 if (nextState == Idle || ce->drainState() != DrainState::Running) {
640 return DrainState::Drained;
641 } else {
642 DPRINTF(Drain, "CopyEngineChannel not drained\n");
643 return DrainState::Draining;
644 }
645 }
646
647 void
648 CopyEngine::serialize(CheckpointOut &cp) const
649 {
650 PciDevice::serialize(cp);
651 regs.serialize(cp);
652 for (int x =0; x < chan.size(); x++)
653 chan[x]->serializeSection(cp, csprintf("channel%d", x));
654 }
655
656 void
657 CopyEngine::unserialize(CheckpointIn &cp)
658 {
659 PciDevice::unserialize(cp);
660 regs.unserialize(cp);
661 for (int x = 0; x < chan.size(); x++)
662 chan[x]->unserializeSection(cp, csprintf("channel%d", x));
663 }
664
665 void
666 CopyEngine::CopyEngineChannel::serialize(CheckpointOut &cp) const
667 {
668 SERIALIZE_SCALAR(channelId);
669 SERIALIZE_SCALAR(busy);
670 SERIALIZE_SCALAR(underReset);
671 SERIALIZE_SCALAR(refreshNext);
672 SERIALIZE_SCALAR(lastDescriptorAddr);
673 SERIALIZE_SCALAR(completionDataReg);
674 SERIALIZE_SCALAR(fetchAddress);
675 int nextState = this->nextState;
676 SERIALIZE_SCALAR(nextState);
677 arrayParamOut(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
678 SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
679 cr.serialize(cp);
680
681 }
682 void
683 CopyEngine::CopyEngineChannel::unserialize(CheckpointIn &cp)
684 {
685 UNSERIALIZE_SCALAR(channelId);
686 UNSERIALIZE_SCALAR(busy);
687 UNSERIALIZE_SCALAR(underReset);
688 UNSERIALIZE_SCALAR(refreshNext);
689 UNSERIALIZE_SCALAR(lastDescriptorAddr);
690 UNSERIALIZE_SCALAR(completionDataReg);
691 UNSERIALIZE_SCALAR(fetchAddress);
692 int nextState;
693 UNSERIALIZE_SCALAR(nextState);
694 this->nextState = (ChannelState)nextState;
695 arrayParamIn(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
696 UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
697 cr.unserialize(cp);
698
699 }
700
701 void
702 CopyEngine::CopyEngineChannel::restartStateMachine()
703 {
704 switch(nextState) {
705 case AddressFetch:
706 fetchNextAddr(lastDescriptorAddr);
707 break;
708 case DescriptorFetch:
709 fetchDescriptor(fetchAddress);
710 break;
711 case DMARead:
712 readCopyBytes();
713 break;
714 case DMAWrite:
715 writeCopyBytes();
716 break;
717 case CompletionWrite:
718 writeCompletionStatus();
719 break;
720 case Idle:
721 break;
722 default:
723 panic("Unknown state for CopyEngineChannel\n");
724 }
725 }
726
727 void
728 CopyEngine::CopyEngineChannel::drainResume()
729 {
730 DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
731 restartStateMachine();
732 }
733
734 CopyEngine *
735 CopyEngineParams::create()
736 {
737 return new CopyEngine(this);
738 }