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