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