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