copy_engine.cc revision 10905
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
60using namespace CopyEngineReg;
61
62CopyEngine::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
80CopyEngine::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
100CopyEngine::~CopyEngine()
101{
102    for (int x = 0; x < chan.size(); x++) {
103        delete chan[x];
104    }
105}
106
107CopyEngine::CopyEngineChannel::~CopyEngineChannel()
108{
109    delete curDmaDesc;
110    delete [] copyBuffer;
111}
112
113BaseMasterPort &
114CopyEngine::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
129BaseMasterPort &
130CopyEngine::CopyEngineChannel::getMasterPort()
131{
132    return cePort;
133}
134
135void
136CopyEngine::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
165Tick
166CopyEngine::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
238void
239CopyEngine::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
288Tick
289CopyEngine::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
362void
363CopyEngine::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
424void
425CopyEngine::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
442void
443CopyEngine::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
461void
462CopyEngine::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
492void
493CopyEngine::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
503void
504CopyEngine::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
513void
514CopyEngine::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
528void
529CopyEngine::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
549void
550CopyEngine::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
582void
583CopyEngine::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
596void
597CopyEngine::CopyEngineChannel::writeStatusComplete()
598{
599    DPRINTF(DMACopyEngine, "Writing completion status complete\n");
600    continueProcessing();
601}
602
603void
604CopyEngine::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
615void
616CopyEngine::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
635bool
636CopyEngine::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
648unsigned int
649CopyEngine::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
661unsigned int
662CopyEngine::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
678void
679CopyEngine::serialize(CheckpointOut &cp) const
680{
681    PciDevice::serialize(cp);
682    regs.serialize(cp);
683    for (int x =0; x < chan.size(); x++)
684        chan[x]->serializeSection(cp, csprintf("channel%d", x));
685}
686
687void
688CopyEngine::unserialize(CheckpointIn &cp)
689{
690    PciDevice::unserialize(cp);
691    regs.unserialize(cp);
692    for (int x = 0; x < chan.size(); x++)
693        chan[x]->unserializeSection(cp, csprintf("channel%d", x));
694}
695
696void
697CopyEngine::CopyEngineChannel::serialize(CheckpointOut &cp) const
698{
699    SERIALIZE_SCALAR(channelId);
700    SERIALIZE_SCALAR(busy);
701    SERIALIZE_SCALAR(underReset);
702    SERIALIZE_SCALAR(refreshNext);
703    SERIALIZE_SCALAR(lastDescriptorAddr);
704    SERIALIZE_SCALAR(completionDataReg);
705    SERIALIZE_SCALAR(fetchAddress);
706    int nextState = this->nextState;
707    SERIALIZE_SCALAR(nextState);
708    arrayParamOut(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
709    SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
710    cr.serialize(cp);
711
712}
713void
714CopyEngine::CopyEngineChannel::unserialize(CheckpointIn &cp)
715{
716    UNSERIALIZE_SCALAR(channelId);
717    UNSERIALIZE_SCALAR(busy);
718    UNSERIALIZE_SCALAR(underReset);
719    UNSERIALIZE_SCALAR(refreshNext);
720    UNSERIALIZE_SCALAR(lastDescriptorAddr);
721    UNSERIALIZE_SCALAR(completionDataReg);
722    UNSERIALIZE_SCALAR(fetchAddress);
723    int nextState;
724    UNSERIALIZE_SCALAR(nextState);
725    this->nextState = (ChannelState)nextState;
726    arrayParamIn(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
727    UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
728    cr.unserialize(cp);
729
730}
731
732void
733CopyEngine::CopyEngineChannel::restartStateMachine()
734{
735    switch(nextState) {
736      case AddressFetch:
737        fetchNextAddr(lastDescriptorAddr);
738        break;
739      case DescriptorFetch:
740        fetchDescriptor(fetchAddress);
741        break;
742      case DMARead:
743        readCopyBytes();
744        break;
745      case DMAWrite:
746        writeCopyBytes();
747        break;
748      case CompletionWrite:
749        writeCompletionStatus();
750        break;
751      case Idle:
752        break;
753      default:
754        panic("Unknown state for CopyEngineChannel\n");
755    }
756}
757
758void
759CopyEngine::drainResume()
760{
761    Drainable::drainResume();
762    for (int x = 0;x < chan.size(); x++)
763        chan[x]->drainResume();
764}
765
766
767void
768CopyEngine::CopyEngineChannel::drainResume()
769{
770    DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
771    restartStateMachine();
772}
773
774CopyEngine *
775CopyEngineParams::create()
776{
777    return new CopyEngine(this);
778}
779