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