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