copy_engine.cc revision 5954
12SN/A/*
211856Sbrandon.potter@amd.com * Copyright (c) 2008 The Regents of The University of Michigan
38852Sandreas.hansson@arm.com * All rights reserved.
48852Sandreas.hansson@arm.com *
58852Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
68852Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
78852Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
88852Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
98852Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
108852Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
118852Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
128852Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
138852Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
148852Sandreas.hansson@arm.com * this software without specific prior written permission.
151762SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272SN/A *
282SN/A * Authors: Ali Saidi
292SN/A */
302SN/A
312SN/A/* @file
322SN/A * Device model for Intel's I/O AT DMA copy engine.
332SN/A */
342SN/A
352SN/A#include <algorithm>
362SN/A
372SN/A#include "base/cp_annotate.hh"
382SN/A#include "base/trace.hh"
392SN/A#include "dev/copy_engine.hh"
402665Ssaidi@eecs.umich.edu#include "mem/packet.hh"
412665Ssaidi@eecs.umich.edu#include "mem/packet_access.hh"
422665Ssaidi@eecs.umich.edu#include "params/CopyEngine.hh"
432665Ssaidi@eecs.umich.edu#include "sim/stats.hh"
4411856Sbrandon.potter@amd.com#include "sim/system.hh"
452SN/A
462SN/Ausing namespace CopyEngineReg;
4711793Sbrandon.potter@amd.comusing namespace std;
4811793Sbrandon.potter@amd.com
498229Snate@binkert.orgCopyEngine::CopyEngine(const Params *p)
502SN/A    : PciDev(p)
516712Snate@binkert.org{
5211800Sbrandon.potter@amd.com    // All Reg regs are initialized to 0 by default
5311911SBrandon.Potter@amd.com    regs.chanCount = p->ChanCnt;
5410930Sbrandon.potter@amd.com    regs.xferCap = findMsbSet(p->XferCap);
552SN/A    regs.attnStatus = 0;
5611800Sbrandon.potter@amd.com
572SN/A    if (regs.chanCount > 64)
5811793Sbrandon.potter@amd.com        fatal("CopyEngine interface doesn't support more than 64 DMA engines\n");
5956SN/A
601158SN/A    for (int x = 0; x < regs.chanCount; x++) {
61146SN/A        CopyEngineChannel *ch = new CopyEngineChannel(this, x);
626658Snate@binkert.org        chan.push_back(ch);
632680Sktlim@umich.edu    }
642378SN/A}
658706Sandreas.hansson@arm.com
665154Sgblack@eecs.umich.edu
6711800Sbrandon.potter@amd.comCopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
6811856Sbrandon.potter@amd.com    : ce(_ce), channelId(cid), busy(false), underReset(false),
6911856Sbrandon.potter@amd.com    refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
7011794Sbrandon.potter@amd.com    latAfterCompletion(ce->params()->latAfterCompletion),
712378SN/A    completionDataReg(0), nextState(Idle), drainEvent(NULL),
722SN/A    fetchCompleteEvent(this), addrCompleteEvent(this),
732715Sstever@eecs.umich.edu    readCompleteEvent(this), writeCompleteEvent(this),
742715Sstever@eecs.umich.edu    statusCompleteEvent(this)
7511911SBrandon.Potter@amd.com
762715Sstever@eecs.umich.edu{
772715Sstever@eecs.umich.edu        cr.status.dma_transfer_status(3);
782715Sstever@eecs.umich.edu        cr.descChainAddr = 0;
7911911SBrandon.Potter@amd.com        cr.completionAddr = 0;
802715Sstever@eecs.umich.edu
812715Sstever@eecs.umich.edu        curDmaDesc = new DmaDesc;
8211911SBrandon.Potter@amd.com        memset(curDmaDesc, 0, sizeof(DmaDesc));
835335Shines@cs.fsu.edu        copyBuffer = new uint8_t[ce->params()->XferCap];
8411911SBrandon.Potter@amd.com}
855335Shines@cs.fsu.edu
8611911SBrandon.Potter@amd.comCopyEngine::~CopyEngine()
874157Sgblack@eecs.umich.edu{
884166Sgblack@eecs.umich.edu    for (int x = 0; x < chan.size(); x++) {
8911911SBrandon.Potter@amd.com        delete chan[x];
906691Stjones1@inf.ed.ac.uk    }
916691Stjones1@inf.ed.ac.uk}
9211911SBrandon.Potter@amd.com
9311723Sar4jc@virginia.eduCopyEngine::CopyEngineChannel::~CopyEngineChannel()
9411723Sar4jc@virginia.edu{
9511911SBrandon.Potter@amd.com    delete curDmaDesc;
962715Sstever@eecs.umich.edu    delete [] copyBuffer;
972715Sstever@eecs.umich.edu    delete cePort;
982715Sstever@eecs.umich.edu}
992715Sstever@eecs.umich.edu
1002715Sstever@eecs.umich.eduvoid
1012SN/ACopyEngine::init()
1022107SN/A{
1032SN/A    PciDev::init();
10412431Sgabeblack@google.com    for (int x = 0; x < chan.size(); x++)
10512431Sgabeblack@google.com        chan[x]->init();
1067532Ssteve.reinhardt@amd.com}
10710299Salexandru.dutu@amd.com
10810554Salexandru.dutu@amd.comvoid
10912431Sgabeblack@google.comCopyEngine::CopyEngineChannel::init()
1108852Sandreas.hansson@arm.com{
11110929Sbrandon.potter@amd.com    Port *peer;
11211851Sbrandon.potter@amd.com
11311851Sbrandon.potter@amd.com    cePort = new DmaPort(ce, ce->sys);
11411851Sbrandon.potter@amd.com    peer = ce->dmaPort->getPeer()->getOwner()->getPort("");
11511801Sbrandon.potter@amd.com    peer->setPeer(cePort);
11611801Sbrandon.potter@amd.com    cePort->setPeer(peer);
11711851Sbrandon.potter@amd.com}
11811885Sbrandon.potter@amd.com
11911886Sbrandon.potter@amd.comvoid
12011886Sbrandon.potter@amd.comCopyEngine::CopyEngineChannel::recvCommand()
1212SN/A{
12211885Sbrandon.potter@amd.com    if (cr.command.start_dma()) {
12311885Sbrandon.potter@amd.com        assert(!busy);
12411885Sbrandon.potter@amd.com        cr.status.dma_transfer_status(0);
12511885Sbrandon.potter@amd.com        nextState = DescriptorFetch;
12611885Sbrandon.potter@amd.com        fetchAddress = cr.descChainAddr;
12711885Sbrandon.potter@amd.com        if (ce->getState() == SimObject::Running)
12811885Sbrandon.potter@amd.com            fetchDescriptor(cr.descChainAddr);
12911886Sbrandon.potter@amd.com    } else if (cr.command.append_dma()) {
13011886Sbrandon.potter@amd.com        if (!busy) {
13111886Sbrandon.potter@amd.com            nextState = AddressFetch;
13211886Sbrandon.potter@amd.com            if (ce->getState() == SimObject::Running)
13311886Sbrandon.potter@amd.com                fetchNextAddr(lastDescriptorAddr);
13411886Sbrandon.potter@amd.com        } else
13511886Sbrandon.potter@amd.com            refreshNext = true;
13611886Sbrandon.potter@amd.com    } else if (cr.command.reset_dma()) {
13711886Sbrandon.potter@amd.com        if (busy)
13811886Sbrandon.potter@amd.com            underReset = true;
13911886Sbrandon.potter@amd.com        else {
14011886Sbrandon.potter@amd.com            cr.status.dma_transfer_status(3);
14111886Sbrandon.potter@amd.com            nextState = Idle;
14211886Sbrandon.potter@amd.com        }
14311886Sbrandon.potter@amd.com    } else if (cr.command.resume_dma() || cr.command.abort_dma() ||
14411886Sbrandon.potter@amd.com            cr.command.suspend_dma())
14511886Sbrandon.potter@amd.com        panic("Resume, Abort, and Suspend are not supported\n");
14611851Sbrandon.potter@amd.com    cr.command(0);
14711851Sbrandon.potter@amd.com}
14811851Sbrandon.potter@amd.com
14911851Sbrandon.potter@amd.comTick
15011851Sbrandon.potter@amd.comCopyEngine::read(PacketPtr pkt)
15111851Sbrandon.potter@amd.com{
15211919SBrandon.Potter@amd.com    int bar;
15311851Sbrandon.potter@amd.com    Addr daddr;
15411851Sbrandon.potter@amd.com
1552SN/A    if (!getBAR(pkt->getAddr(), bar, daddr))
1562SN/A        panic("Invalid PCI memory access to unmapped memory.\n");
1572SN/A
15811886Sbrandon.potter@amd.com    // Only Memory register BAR is allowed
15911886Sbrandon.potter@amd.com    assert(bar == 0);
16011886Sbrandon.potter@amd.com
16111920SBrandon.Potter@amd.com    int size = pkt->getSize();
16211920SBrandon.Potter@amd.com    if (size != sizeof(uint64_t) && size != sizeof(uint32_t) &&
16311920SBrandon.Potter@amd.com        size != sizeof(uint16_t) && size != sizeof(uint8_t)) {
16411920SBrandon.Potter@amd.com        panic("Unknown size for MMIO access: %d\n", pkt->getSize());
16511920SBrandon.Potter@amd.com    }
16611920SBrandon.Potter@amd.com
16711920SBrandon.Potter@amd.com    DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size);
16811920SBrandon.Potter@amd.com
16911920SBrandon.Potter@amd.com    pkt->allocate();
17011886Sbrandon.potter@amd.com
17111886Sbrandon.potter@amd.com    ///
17211886Sbrandon.potter@amd.com    /// Handle read of register here
17311886Sbrandon.potter@amd.com    ///
17411886Sbrandon.potter@amd.com
17511886Sbrandon.potter@amd.com    if (daddr < 0x80) {
17611886Sbrandon.potter@amd.com        switch (daddr) {
17711886Sbrandon.potter@amd.com          case GEN_CHANCOUNT:
17811886Sbrandon.potter@amd.com            assert(size == sizeof(regs.chanCount));
17911886Sbrandon.potter@amd.com            pkt->set<uint8_t>(regs.chanCount);
18011886Sbrandon.potter@amd.com            break;
18111886Sbrandon.potter@amd.com          case GEN_XFERCAP:
18211886Sbrandon.potter@amd.com            assert(size == sizeof(regs.xferCap));
18311886Sbrandon.potter@amd.com            pkt->set<uint8_t>(regs.xferCap);
18411886Sbrandon.potter@amd.com            break;
18511886Sbrandon.potter@amd.com          case GEN_INTRCTRL:
18611886Sbrandon.potter@amd.com            assert(size == sizeof(uint8_t));
18711886Sbrandon.potter@amd.com            pkt->set<uint8_t>(regs.intrctrl());
18811886Sbrandon.potter@amd.com            regs.intrctrl.master_int_enable(0);
18911886Sbrandon.potter@amd.com            break;
19011886Sbrandon.potter@amd.com          case GEN_ATTNSTATUS:
19111886Sbrandon.potter@amd.com            assert(size == sizeof(regs.attnStatus));
19211886Sbrandon.potter@amd.com            pkt->set<uint32_t>(regs.attnStatus);
19311886Sbrandon.potter@amd.com            regs.attnStatus = 0;
19411886Sbrandon.potter@amd.com            break;
19511886Sbrandon.potter@amd.com          default:
19611886Sbrandon.potter@amd.com            panic("Read request to unknown register number: %#x\n", daddr);
19711886Sbrandon.potter@amd.com        }
19811886Sbrandon.potter@amd.com        pkt->makeAtomicResponse();
19911886Sbrandon.potter@amd.com        return pioDelay;
20011886Sbrandon.potter@amd.com    }
20111886Sbrandon.potter@amd.com
20211886Sbrandon.potter@amd.com
20311886Sbrandon.potter@amd.com    // Find which channel we're accessing
20411886Sbrandon.potter@amd.com    int chanid = 0;
20511886Sbrandon.potter@amd.com    daddr -= 0x80;
20611886Sbrandon.potter@amd.com    while (daddr >= 0x80) {
20711886Sbrandon.potter@amd.com        chanid++;
20811886Sbrandon.potter@amd.com        daddr -= 0x80;
20911886Sbrandon.potter@amd.com    }
21011886Sbrandon.potter@amd.com
21111886Sbrandon.potter@amd.com    if (chanid >= regs.chanCount)
21211886Sbrandon.potter@amd.com        panic("Access to channel %d (device only configured for %d channels)",
21311886Sbrandon.potter@amd.com                chanid, regs.chanCount);
21411886Sbrandon.potter@amd.com
21511886Sbrandon.potter@amd.com    ///
21611886Sbrandon.potter@amd.com    /// Channel registers are handled here
21711886Sbrandon.potter@amd.com    ///
21811886Sbrandon.potter@amd.com    chan[chanid]->channelRead(pkt, daddr, size);
21911886Sbrandon.potter@amd.com
22011886Sbrandon.potter@amd.com    pkt->makeAtomicResponse();
22111886Sbrandon.potter@amd.com    return pioDelay;
22211886Sbrandon.potter@amd.com}
22311886Sbrandon.potter@amd.com
22411886Sbrandon.potter@amd.comvoid
22511886Sbrandon.potter@amd.comCopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size)
22611886Sbrandon.potter@amd.com{
22711886Sbrandon.potter@amd.com    switch (daddr) {
22811886Sbrandon.potter@amd.com      case CHAN_CONTROL:
22911886Sbrandon.potter@amd.com        assert(size == sizeof(uint16_t));
23011886Sbrandon.potter@amd.com        pkt->set<uint16_t>(cr.ctrl());
23111886Sbrandon.potter@amd.com        cr.ctrl.in_use(1);
23211886Sbrandon.potter@amd.com        break;
23311886Sbrandon.potter@amd.com      case CHAN_STATUS:
23411886Sbrandon.potter@amd.com        assert(size == sizeof(uint64_t));
23511886Sbrandon.potter@amd.com        pkt->set<uint64_t>(cr.status() | ~busy);
23611886Sbrandon.potter@amd.com        break;
23711886Sbrandon.potter@amd.com      case CHAN_CHAINADDR:
23811886Sbrandon.potter@amd.com        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
23911886Sbrandon.potter@amd.com        if (size == sizeof(uint64_t))
24011886Sbrandon.potter@amd.com            pkt->set<uint64_t>(cr.descChainAddr);
24111886Sbrandon.potter@amd.com        else
24211886Sbrandon.potter@amd.com            pkt->set<uint32_t>(bits(cr.descChainAddr,0,31));
24311886Sbrandon.potter@amd.com        break;
24411886Sbrandon.potter@amd.com      case CHAN_CHAINADDR_HIGH:
24511886Sbrandon.potter@amd.com        assert(size == sizeof(uint32_t));
24611886Sbrandon.potter@amd.com        pkt->set<uint32_t>(bits(cr.descChainAddr,32,63));
24711886Sbrandon.potter@amd.com        break;
24811886Sbrandon.potter@amd.com      case CHAN_COMMAND:
24911886Sbrandon.potter@amd.com        assert(size == sizeof(uint8_t));
2502SN/A        pkt->set<uint32_t>(cr.command());
2512SN/A        break;
25211522Sstephan.diestelhorst@arm.com      case CHAN_CMPLNADDR:
25311522Sstephan.diestelhorst@arm.com        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
254729SN/A        if (size == sizeof(uint64_t))
2552SN/A            pkt->set<uint64_t>(cr.completionAddr);
25611886Sbrandon.potter@amd.com        else
25711886Sbrandon.potter@amd.com            pkt->set<uint32_t>(bits(cr.completionAddr,0,31));
2582SN/A        break;
2592SN/A      case CHAN_CMPLNADDR_HIGH:
2602SN/A        assert(size == sizeof(uint32_t));
2612SN/A        pkt->set<uint32_t>(bits(cr.completionAddr,32,63));
2625713Shsul@eecs.umich.edu        break;
2635713Shsul@eecs.umich.edu      case CHAN_ERROR:
2642SN/A        assert(size == sizeof(uint32_t));
26511886Sbrandon.potter@amd.com        pkt->set<uint32_t>(cr.error());
26611886Sbrandon.potter@amd.com        break;
26711886Sbrandon.potter@amd.com      default:
2685512SMichael.Adler@intel.com        panic("Read request to unknown channel register number: (%d)%#x\n",
26911919SBrandon.Potter@amd.com                channelId, daddr);
2702SN/A    }
2712SN/A}
2721395SN/A
27311886Sbrandon.potter@amd.com
27411886Sbrandon.potter@amd.comTick
27511886Sbrandon.potter@amd.comCopyEngine::write(PacketPtr pkt)
27611886Sbrandon.potter@amd.com{
27711886Sbrandon.potter@amd.com    int bar;
27811886Sbrandon.potter@amd.com    Addr daddr;
27911886Sbrandon.potter@amd.com
28011886Sbrandon.potter@amd.com
28111886Sbrandon.potter@amd.com    if (!getBAR(pkt->getAddr(), bar, daddr))
28211886Sbrandon.potter@amd.com        panic("Invalid PCI memory access to unmapped memory.\n");
28311886Sbrandon.potter@amd.com
28411886Sbrandon.potter@amd.com    // Only Memory register BAR is allowed
28511886Sbrandon.potter@amd.com    assert(bar == 0);
2867532Ssteve.reinhardt@amd.com
2871395SN/A    int size = pkt->getSize();
2885713Shsul@eecs.umich.edu
2895713Shsul@eecs.umich.edu    ///
2902378SN/A    /// Handle write of register here
2912680Sktlim@umich.edu    ///
2925713Shsul@eecs.umich.edu
2931395SN/A    if (size == sizeof(uint64_t)) {
2941634SN/A        uint64_t val M5_VAR_USED = pkt->get<uint64_t>();
29510407Smitch.hayenga@arm.com        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
29610298Salexandru.dutu@amd.com    } else if (size == sizeof(uint32_t)) {
29710298Salexandru.dutu@amd.com        uint32_t val M5_VAR_USED = pkt->get<uint32_t>();
2981395SN/A        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
2992SN/A    } else if (size == sizeof(uint16_t)) {
30010913Sandreas.sandberg@arm.com        uint16_t val M5_VAR_USED = pkt->get<uint16_t>();
30110913Sandreas.sandberg@arm.com        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
30210905Sandreas.sandberg@arm.com    } else if (size == sizeof(uint8_t)) {
30311856Sbrandon.potter@amd.com        uint8_t val M5_VAR_USED = pkt->get<uint8_t>();
30410913Sandreas.sandberg@arm.com        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
30510905Sandreas.sandberg@arm.com    } else {
30610905Sandreas.sandberg@arm.com        panic("Unknown size for MMIO access: %d\n", size);
3078601Ssteve.reinhardt@amd.com    }
3088601Ssteve.reinhardt@amd.com
3098601Ssteve.reinhardt@amd.com    if (daddr < 0x80) {
31010318Sandreas.hansson@arm.com        switch (daddr) {
3118601Ssteve.reinhardt@amd.com          case GEN_CHANCOUNT:
31211294Sandreas.hansson@arm.com          case GEN_XFERCAP:
31311294Sandreas.hansson@arm.com          case GEN_ATTNSTATUS:
3148601Ssteve.reinhardt@amd.com            DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
3158601Ssteve.reinhardt@amd.com                    daddr);
31611886Sbrandon.potter@amd.com            break;
31711886Sbrandon.potter@amd.com          case GEN_INTRCTRL:
31811886Sbrandon.potter@amd.com            regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1));
31911886Sbrandon.potter@amd.com            break;
32011886Sbrandon.potter@amd.com          default:
32111886Sbrandon.potter@amd.com            panic("Read request to unknown register number: %#x\n", daddr);
32211886Sbrandon.potter@amd.com        }
32311886Sbrandon.potter@amd.com        pkt->makeAtomicResponse();
32411886Sbrandon.potter@amd.com        return pioDelay;
32511886Sbrandon.potter@amd.com    }
32611886Sbrandon.potter@amd.com
32711886Sbrandon.potter@amd.com    // Find which channel we're accessing
32811886Sbrandon.potter@amd.com    int chanid = 0;
32911886Sbrandon.potter@amd.com    daddr -= 0x80;
33011886Sbrandon.potter@amd.com    while (daddr >= 0x80) {
33111886Sbrandon.potter@amd.com        chanid++;
33211886Sbrandon.potter@amd.com        daddr -= 0x80;
33311886Sbrandon.potter@amd.com    }
33411886Sbrandon.potter@amd.com
3354434Ssaidi@eecs.umich.edu    if (chanid >= regs.chanCount)
3368539Sgblack@eecs.umich.edu        panic("Access to channel %d (device only configured for %d channels)",
3374434Ssaidi@eecs.umich.edu                chanid, regs.chanCount);
33811905SBrandon.Potter@amd.com
33911905SBrandon.Potter@amd.com    ///
34011905SBrandon.Potter@amd.com    /// Channel registers are handled here
34111905SBrandon.Potter@amd.com    ///
3428539Sgblack@eecs.umich.edu    chan[chanid]->channelWrite(pkt, daddr, size);
3438539Sgblack@eecs.umich.edu
34411905SBrandon.Potter@amd.com    pkt->makeAtomicResponse();
34510318Sandreas.hansson@arm.com    return pioDelay;
3464434Ssaidi@eecs.umich.edu}
3474434Ssaidi@eecs.umich.edu
3484434Ssaidi@eecs.umich.eduvoid
3498539Sgblack@eecs.umich.eduCopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size)
3508539Sgblack@eecs.umich.edu{
35111905SBrandon.Potter@amd.com    switch (daddr) {
35211905SBrandon.Potter@amd.com      case CHAN_CONTROL:
35311905SBrandon.Potter@amd.com        assert(size == sizeof(uint16_t));
35411905SBrandon.Potter@amd.com        int old_int_disable;
3555154Sgblack@eecs.umich.edu        old_int_disable = cr.ctrl.interrupt_disable();
35611905SBrandon.Potter@amd.com        cr.ctrl(pkt->get<uint16_t>());
3575823Ssaidi@eecs.umich.edu        if (cr.ctrl.interrupt_disable())
35811906SBrandon.Potter@amd.com            cr.ctrl.interrupt_disable(0);
35911905SBrandon.Potter@amd.com        else
3604434Ssaidi@eecs.umich.edu            cr.ctrl.interrupt_disable(old_int_disable);
3614434Ssaidi@eecs.umich.edu        break;
3624434Ssaidi@eecs.umich.edu      case CHAN_STATUS:
3634434Ssaidi@eecs.umich.edu        assert(size == sizeof(uint64_t));
3644434Ssaidi@eecs.umich.edu        DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
3655282Srstrong@cs.ucsd.edu                    daddr);
36610905Sandreas.sandberg@arm.com        break;
3673311Ssaidi@eecs.umich.edu      case CHAN_CHAINADDR:
36812283Saustinharris@utexas.edu        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
36910905Sandreas.sandberg@arm.com        if (size == sizeof(uint64_t))
37011856Sbrandon.potter@amd.com            cr.descChainAddr = pkt->get<uint64_t>();
37111856Sbrandon.potter@amd.com        else
37211856Sbrandon.potter@amd.com            cr.descChainAddr =  (uint64_t)pkt->get<uint32_t>() |
37311856Sbrandon.potter@amd.com                (cr.descChainAddr & ~mask(32));
37411856Sbrandon.potter@amd.com        DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
37511856Sbrandon.potter@amd.com        break;
37611856Sbrandon.potter@amd.com      case CHAN_CHAINADDR_HIGH:
37711856Sbrandon.potter@amd.com        assert(size == sizeof(uint32_t));
37811856Sbrandon.potter@amd.com        cr.descChainAddr =  ((uint64_t)pkt->get<uint32_t>() <<32) |
37911856Sbrandon.potter@amd.com            (cr.descChainAddr & mask(32));
3803311Ssaidi@eecs.umich.edu        DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
3813311Ssaidi@eecs.umich.edu        break;
3823311Ssaidi@eecs.umich.edu      case CHAN_COMMAND:
3833311Ssaidi@eecs.umich.edu        assert(size == sizeof(uint8_t));
38410905Sandreas.sandberg@arm.com        cr.command(pkt->get<uint8_t>());
3853311Ssaidi@eecs.umich.edu        recvCommand();
38612283Saustinharris@utexas.edu        break;
38710905Sandreas.sandberg@arm.com      case CHAN_CMPLNADDR:
38811856Sbrandon.potter@amd.com        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
38911856Sbrandon.potter@amd.com        if (size == sizeof(uint64_t))
39011856Sbrandon.potter@amd.com            cr.completionAddr = pkt->get<uint64_t>();
39111856Sbrandon.potter@amd.com        else
39211856Sbrandon.potter@amd.com            cr.completionAddr =  pkt->get<uint32_t>() |
39311856Sbrandon.potter@amd.com                (cr.completionAddr & ~mask(32));
39411856Sbrandon.potter@amd.com        break;
39511856Sbrandon.potter@amd.com      case CHAN_CMPLNADDR_HIGH:
39611856Sbrandon.potter@amd.com        assert(size == sizeof(uint32_t));
39711856Sbrandon.potter@amd.com        cr.completionAddr =  ((uint64_t)pkt->get<uint32_t>() <<32) |
3986820SLisa.Hsu@amd.com            (cr.completionAddr & mask(32));
3996820SLisa.Hsu@amd.com        break;
40010930Sbrandon.potter@amd.com      case CHAN_ERROR:
40110929Sbrandon.potter@amd.com        assert(size == sizeof(uint32_t));
4023311Ssaidi@eecs.umich.edu        cr.error(~pkt->get<uint32_t>() & cr.error());
4032SN/A        break;
4049110Ssteve.reinhardt@amd.com      default:
40510558Salexandru.dutu@amd.com        panic("Read request to unknown channel register number: (%d)%#x\n",
4069110Ssteve.reinhardt@amd.com                channelId, daddr);
40710558Salexandru.dutu@amd.com    }
40811294Sandreas.hansson@arm.com}
4099110Ssteve.reinhardt@amd.com
4109110Ssteve.reinhardt@amd.comvoid
4119110Ssteve.reinhardt@amd.comCopyEngine::regStats()
4122378SN/A{
41311877Sbrandon.potter@amd.com    using namespace Stats;
4142093SN/A    bytesCopied
41511886Sbrandon.potter@amd.com        .init(regs.chanCount)
4162093SN/A        .name(name() + ".bytes_copied")
4172093SN/A        .desc("Number of bytes copied by each engine")
41811919SBrandon.Potter@amd.com        .flags(total)
4192093SN/A        ;
4202093SN/A    copiesProcessed
42111877Sbrandon.potter@amd.com        .init(regs.chanCount)
4222093SN/A        .name(name() + ".copies_processed")
4232SN/A        .desc("Number of copies processed by each engine")
4246701Sgblack@eecs.umich.edu        .flags(total)
42511851Sbrandon.potter@amd.com        ;
4266701Sgblack@eecs.umich.edu}
4276701Sgblack@eecs.umich.edu
4286701Sgblack@eecs.umich.eduvoid
4296701Sgblack@eecs.umich.eduCopyEngine::CopyEngineChannel::fetchDescriptor(Addr address)
43010496Ssteve.reinhardt@amd.com{
43111851Sbrandon.potter@amd.com    anDq();
43210496Ssteve.reinhardt@amd.com    anBegin("FetchDescriptor");
43310496Ssteve.reinhardt@amd.com    DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n",
43410496Ssteve.reinhardt@amd.com           address, ce->platform->pciToDma(address));
43510496Ssteve.reinhardt@amd.com    assert(address);
43610496Ssteve.reinhardt@amd.com    busy = true;
43710496Ssteve.reinhardt@amd.com
43811919SBrandon.Potter@amd.com    DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n",
43910496Ssteve.reinhardt@amd.com            ce->platform->pciToDma(address), sizeof(DmaDesc), curDmaDesc);
44010496Ssteve.reinhardt@amd.com
44111389Sbrandon.potter@amd.com    cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address),
44211851Sbrandon.potter@amd.com            sizeof(DmaDesc), &fetchCompleteEvent, (uint8_t*)curDmaDesc,
44311389Sbrandon.potter@amd.com            latBeforeBegin);
44411389Sbrandon.potter@amd.com    lastDescriptorAddr = address;
44511389Sbrandon.potter@amd.com}
44611389Sbrandon.potter@amd.com
44711389Sbrandon.potter@amd.comvoid
44811389Sbrandon.potter@amd.comCopyEngine::CopyEngineChannel::fetchDescComplete()
44911389Sbrandon.potter@amd.com{
45011389Sbrandon.potter@amd.com    DPRINTF(DMACopyEngine, "Read of descriptor complete\n");
45111389Sbrandon.potter@amd.com
45211389Sbrandon.potter@amd.com    if ((curDmaDesc->command & DESC_CTRL_NULL)) {
45311389Sbrandon.potter@amd.com        DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n");
45411389Sbrandon.potter@amd.com        assert(!(curDmaDesc->command & DESC_CTRL_CP_STS));
45511905SBrandon.Potter@amd.com        if (curDmaDesc->command & DESC_CTRL_CP_STS) {
45611905SBrandon.Potter@amd.com            panic("Shouldn't be able to get here\n");
45711389Sbrandon.potter@amd.com            nextState = CompletionWrite;
45811389Sbrandon.potter@amd.com            if (inDrain()) return;
45911389Sbrandon.potter@amd.com            writeCompletionStatus();
46011389Sbrandon.potter@amd.com        } else {
46111905SBrandon.Potter@amd.com            anBegin("Idle");
46211905SBrandon.Potter@amd.com            anWait();
46311389Sbrandon.potter@amd.com            busy = false;
46411389Sbrandon.potter@amd.com            nextState = Idle;
46511389Sbrandon.potter@amd.com            inDrain();
46611389Sbrandon.potter@amd.com        }
46711392Sbrandon.potter@amd.com        return;
46811851Sbrandon.potter@amd.com    }
46911392Sbrandon.potter@amd.com
47011392Sbrandon.potter@amd.com    if (curDmaDesc->command & ~DESC_CTRL_CP_STS)
47111392Sbrandon.potter@amd.com        panic("Descriptor has flag other that completion status set\n");
47211392Sbrandon.potter@amd.com
47311389Sbrandon.potter@amd.com    nextState = DMARead;
47411851Sbrandon.potter@amd.com    if (inDrain()) return;
47511389Sbrandon.potter@amd.com    readCopyBytes();
47611392Sbrandon.potter@amd.com}
47711389Sbrandon.potter@amd.com
47811389Sbrandon.potter@amd.comvoid
47911389Sbrandon.potter@amd.comCopyEngine::CopyEngineChannel::readCopyBytes()
48011389Sbrandon.potter@amd.com{
48111389Sbrandon.potter@amd.com    anBegin("ReadCopyBytes");
48211851Sbrandon.potter@amd.com    DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n",
48311389Sbrandon.potter@amd.com           curDmaDesc->len, curDmaDesc->dest,
48411392Sbrandon.potter@amd.com           ce->platform->pciToDma(curDmaDesc->src));
48511389Sbrandon.potter@amd.com    cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(curDmaDesc->src),
48611389Sbrandon.potter@amd.com            curDmaDesc->len, &readCompleteEvent, copyBuffer, 0);
48711389Sbrandon.potter@amd.com}
48811389Sbrandon.potter@amd.com
48911851Sbrandon.potter@amd.comvoid
49011851Sbrandon.potter@amd.comCopyEngine::CopyEngineChannel::readCopyBytesComplete()
4912715Sstever@eecs.umich.edu{
49211919SBrandon.Potter@amd.com    DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n");
4932715Sstever@eecs.umich.edu
49411140Sjthestness@gmail.com    nextState = DMAWrite;
49511140Sjthestness@gmail.com    if (inDrain()) return;
49611851Sbrandon.potter@amd.com    writeCopyBytes();
49711851Sbrandon.potter@amd.com}
49811140Sjthestness@gmail.com
49911140Sjthestness@gmail.comvoid
50011851Sbrandon.potter@amd.comCopyEngine::CopyEngineChannel::writeCopyBytes()
50111919SBrandon.Potter@amd.com{
50211851Sbrandon.potter@amd.com    anBegin("WriteCopyBytes");
5032715Sstever@eecs.umich.edu    DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n",
5042715Sstever@eecs.umich.edu           curDmaDesc->len, curDmaDesc->dest,
5055089Sgblack@eecs.umich.edu           ce->platform->pciToDma(curDmaDesc->dest));
50611851Sbrandon.potter@amd.com
5075753Ssteve.reinhardt@amd.com    cePort->dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(curDmaDesc->dest),
5085753Ssteve.reinhardt@amd.com            curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0);
50911851Sbrandon.potter@amd.com
5105753Ssteve.reinhardt@amd.com    ce->bytesCopied[channelId] += curDmaDesc->len;
5115753Ssteve.reinhardt@amd.com    ce->copiesProcessed[channelId]++;
5125753Ssteve.reinhardt@amd.com}
5132715Sstever@eecs.umich.edu
51411851Sbrandon.potter@amd.comvoid
5152715Sstever@eecs.umich.eduCopyEngine::CopyEngineChannel::writeCopyBytesComplete()
5162715Sstever@eecs.umich.edu{
5172715Sstever@eecs.umich.edu    DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n",
5182715Sstever@eecs.umich.edu            curDmaDesc->user1);
5192715Sstever@eecs.umich.edu
5202715Sstever@eecs.umich.edu    cr.status.compl_desc_addr(lastDescriptorAddr >> 6);
52111851Sbrandon.potter@amd.com    completionDataReg = cr.status() | 1;
52211851Sbrandon.potter@amd.com
5232715Sstever@eecs.umich.edu    anQ("DMAUsedDescQ", channelId, 1);
52411851Sbrandon.potter@amd.com    anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len);
5255753Ssteve.reinhardt@amd.com    if (curDmaDesc->command & DESC_CTRL_CP_STS) {
5265753Ssteve.reinhardt@amd.com        nextState = CompletionWrite;
5275753Ssteve.reinhardt@amd.com        if (inDrain()) return;
5282715Sstever@eecs.umich.edu        writeCompletionStatus();
52911851Sbrandon.potter@amd.com        return;
53011851Sbrandon.potter@amd.com    }
5314111Sgblack@eecs.umich.edu
53211851Sbrandon.potter@amd.com    continueProcessing();
5334111Sgblack@eecs.umich.edu}
5342715Sstever@eecs.umich.edu
5352715Sstever@eecs.umich.eduvoid
5362715Sstever@eecs.umich.eduCopyEngine::CopyEngineChannel::continueProcessing()
53711851Sbrandon.potter@amd.com{
5382715Sstever@eecs.umich.edu    busy = false;
5395753Ssteve.reinhardt@amd.com
5402715Sstever@eecs.umich.edu    if (underReset) {
5412715Sstever@eecs.umich.edu        anBegin("Reset");
5422715Sstever@eecs.umich.edu        anWait();
5434157Sgblack@eecs.umich.edu        underReset = false;
54411851Sbrandon.potter@amd.com        refreshNext = false;
54511851Sbrandon.potter@amd.com        busy = false;
5464166Sgblack@eecs.umich.edu        nextState = Idle;
54711851Sbrandon.potter@amd.com        return;
5485753Ssteve.reinhardt@amd.com    }
5495753Ssteve.reinhardt@amd.com
5505753Ssteve.reinhardt@amd.com    if (curDmaDesc->next) {
5514166Sgblack@eecs.umich.edu        nextState = DescriptorFetch;
55211851Sbrandon.potter@amd.com        fetchAddress = curDmaDesc->next;
55311851Sbrandon.potter@amd.com        if (inDrain()) return;
5545874Sgblack@eecs.umich.edu        fetchDescriptor(curDmaDesc->next);
55511851Sbrandon.potter@amd.com    } else if (refreshNext) {
5565874Sgblack@eecs.umich.edu        nextState = AddressFetch;
5574166Sgblack@eecs.umich.edu        refreshNext = false;
5585753Ssteve.reinhardt@amd.com        if (inDrain()) return;
5594157Sgblack@eecs.umich.edu        fetchNextAddr(lastDescriptorAddr);
5604157Sgblack@eecs.umich.edu    } else {
5614157Sgblack@eecs.umich.edu        inDrain();
5622715Sstever@eecs.umich.edu        nextState = Idle;
56311851Sbrandon.potter@amd.com        anWait();
5642715Sstever@eecs.umich.edu        anBegin("Idle");
56511851Sbrandon.potter@amd.com    }
5665753Ssteve.reinhardt@amd.com}
5675753Ssteve.reinhardt@amd.com
5685753Ssteve.reinhardt@amd.comvoid
5692715Sstever@eecs.umich.eduCopyEngine::CopyEngineChannel::writeCompletionStatus()
57011851Sbrandon.potter@amd.com{
5712715Sstever@eecs.umich.edu    anBegin("WriteCompletionStatus");
5722715Sstever@eecs.umich.edu    DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n",
5732715Sstever@eecs.umich.edu            completionDataReg, cr.completionAddr,
5742715Sstever@eecs.umich.edu            ce->platform->pciToDma(cr.completionAddr));
5752715Sstever@eecs.umich.edu
5765335Shines@cs.fsu.edu    cePort->dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(cr.completionAddr),
57711851Sbrandon.potter@amd.com            sizeof(completionDataReg), &statusCompleteEvent,
57810037SARM gem5 Developers            (uint8_t*)&completionDataReg, latAfterCompletion);
57910037SARM gem5 Developers}
5805335Shines@cs.fsu.edu
58111851Sbrandon.potter@amd.comvoid
5825753Ssteve.reinhardt@amd.comCopyEngine::CopyEngineChannel::writeStatusComplete()
5835753Ssteve.reinhardt@amd.com{
5845753Ssteve.reinhardt@amd.com    DPRINTF(DMACopyEngine, "Writing completion status complete\n");
5855335Shines@cs.fsu.edu    continueProcessing();
58610037SARM gem5 Developers}
58711851Sbrandon.potter@amd.com
58811851Sbrandon.potter@amd.comvoid
58910037SARM gem5 DevelopersCopyEngine::CopyEngineChannel::fetchNextAddr(Addr address)
59011851Sbrandon.potter@amd.com{
59111851Sbrandon.potter@amd.com    anBegin("FetchNextAddr");
59210037SARM gem5 Developers    DPRINTF(DMACopyEngine, "Fetching next address...\n");
5935335Shines@cs.fsu.edu    busy = true;
59410810Sbr@bsdpad.com    cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address +
59510810Sbr@bsdpad.com                offsetof(DmaDesc, next)), sizeof(Addr), &addrCompleteEvent,
59611851Sbrandon.potter@amd.com            (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0);
59711851Sbrandon.potter@amd.com}
59810810Sbr@bsdpad.com
59911851Sbrandon.potter@amd.comvoid
60011851Sbrandon.potter@amd.comCopyEngine::CopyEngineChannel::fetchAddrComplete()
60110810Sbr@bsdpad.com{
60210810Sbr@bsdpad.com    DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n",
6036392Ssaidi@eecs.umich.edu            curDmaDesc->next);
6046392Ssaidi@eecs.umich.edu    if (!curDmaDesc->next) {
6056392Ssaidi@eecs.umich.edu        DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n");
6065335Shines@cs.fsu.edu        busy = false;
6075335Shines@cs.fsu.edu        nextState = Idle;
6085335Shines@cs.fsu.edu        anWait();
6096691Stjones1@inf.ed.ac.uk        anBegin("Idle");
61011851Sbrandon.potter@amd.com        inDrain();
6116691Stjones1@inf.ed.ac.uk        return;
61211851Sbrandon.potter@amd.com    }
6136691Stjones1@inf.ed.ac.uk    nextState = DescriptorFetch;
6146691Stjones1@inf.ed.ac.uk    fetchAddress = curDmaDesc->next;
6156691Stjones1@inf.ed.ac.uk    if (inDrain()) return;
6166691Stjones1@inf.ed.ac.uk    fetchDescriptor(curDmaDesc->next);
61711851Sbrandon.potter@amd.com}
6186691Stjones1@inf.ed.ac.uk
6196691Stjones1@inf.ed.ac.ukbool
6206691Stjones1@inf.ed.ac.ukCopyEngine::CopyEngineChannel::inDrain()
6216691Stjones1@inf.ed.ac.uk{
6226691Stjones1@inf.ed.ac.uk    if (ce->getState() == SimObject::Draining) {
62311723Sar4jc@virginia.edu        DPRINTF(DMACopyEngine, "processing drain\n");
62411851Sbrandon.potter@amd.com        assert(drainEvent);
62511723Sar4jc@virginia.edu        drainEvent->process();
62611851Sbrandon.potter@amd.com        drainEvent = NULL;
62711723Sar4jc@virginia.edu    }
62811723Sar4jc@virginia.edu
62911723Sar4jc@virginia.edu    return ce->getState() != SimObject::Running;
63011723Sar4jc@virginia.edu}
63111851Sbrandon.potter@amd.com
63211723Sar4jc@virginia.eduunsigned int
63311723Sar4jc@virginia.eduCopyEngine::CopyEngineChannel::drain(Event *de)
63411723Sar4jc@virginia.edu{
63511723Sar4jc@virginia.edu    if (nextState == Idle || ce->getState() != SimObject::Running)
6362715Sstever@eecs.umich.edu        return 0;
6372715Sstever@eecs.umich.edu    unsigned int count = 1;
6382715Sstever@eecs.umich.edu    count += cePort->drain(de);
6392715Sstever@eecs.umich.edu
64011919SBrandon.Potter@amd.com    DPRINTF(DMACopyEngine, "unable to drain, returning %d\n", count);
6412715Sstever@eecs.umich.edu    drainEvent = de;
6422715Sstever@eecs.umich.edu    return count;
6432715Sstever@eecs.umich.edu}
64411854Sbrandon.potter@amd.com
64511854Sbrandon.potter@amd.comunsigned int
64611854Sbrandon.potter@amd.comCopyEngine::drain(Event *de)
64711854Sbrandon.potter@amd.com{
64811854Sbrandon.potter@amd.com    unsigned int count;
64911854Sbrandon.potter@amd.com    count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de);
65011854Sbrandon.potter@amd.com    for (int x = 0;x < chan.size(); x++)
65111854Sbrandon.potter@amd.com        count += chan[x]->drain(de);
65211854Sbrandon.potter@amd.com
65311854Sbrandon.potter@amd.com    if (count)
65411854Sbrandon.potter@amd.com        changeState(Draining);
65511854Sbrandon.potter@amd.com    else
65611854Sbrandon.potter@amd.com        changeState(Drained);
65711854Sbrandon.potter@amd.com
658    DPRINTF(DMACopyEngine, "call to CopyEngine::drain() returning %d\n", count);
659    return count;
660}
661
662void
663CopyEngine::serialize(std::ostream &os)
664{
665    PciDev::serialize(os);
666    regs.serialize(os);
667    for (int x =0; x < chan.size(); x++) {
668        nameOut(os, csprintf("%s.channel%d", name(), x));
669        chan[x]->serialize(os);
670    }
671}
672
673void
674CopyEngine::unserialize(Checkpoint *cp, const std::string &section)
675{
676    PciDev::unserialize(cp, section);
677    regs.unserialize(cp, section);
678    for (int x = 0; x < chan.size(); x++)
679        chan[x]->unserialize(cp, csprintf("%s.channel%d", section, x));
680}
681
682void
683CopyEngine::CopyEngineChannel::serialize(std::ostream &os)
684{
685    SERIALIZE_SCALAR(channelId);
686    SERIALIZE_SCALAR(busy);
687    SERIALIZE_SCALAR(underReset);
688    SERIALIZE_SCALAR(refreshNext);
689    SERIALIZE_SCALAR(lastDescriptorAddr);
690    SERIALIZE_SCALAR(completionDataReg);
691    SERIALIZE_SCALAR(fetchAddress);
692    int nextState = this->nextState;
693    SERIALIZE_SCALAR(nextState);
694    arrayParamOut(os, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
695    SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
696    cr.serialize(os);
697
698}
699void
700CopyEngine::CopyEngineChannel::unserialize(Checkpoint *cp, const std::string &section)
701{
702    UNSERIALIZE_SCALAR(channelId);
703    UNSERIALIZE_SCALAR(busy);
704    UNSERIALIZE_SCALAR(underReset);
705    UNSERIALIZE_SCALAR(refreshNext);
706    UNSERIALIZE_SCALAR(lastDescriptorAddr);
707    UNSERIALIZE_SCALAR(completionDataReg);
708    UNSERIALIZE_SCALAR(fetchAddress);
709    int nextState;
710    UNSERIALIZE_SCALAR(nextState);
711    this->nextState = (ChannelState)nextState;
712    arrayParamIn(cp, section, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
713    UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
714    cr.unserialize(cp, section);
715
716}
717
718void
719CopyEngine::CopyEngineChannel::restartStateMachine()
720{
721    switch(nextState) {
722      case AddressFetch:
723        fetchNextAddr(lastDescriptorAddr);
724        break;
725      case DescriptorFetch:
726        fetchDescriptor(fetchAddress);
727        break;
728      case DMARead:
729        readCopyBytes();
730        break;
731      case DMAWrite:
732        writeCopyBytes();
733        break;
734      case CompletionWrite:
735        writeCompletionStatus();
736        break;
737      case Idle:
738        break;
739      default:
740        panic("Unknown state for CopyEngineChannel\n");
741    }
742}
743
744void
745CopyEngine::resume()
746{
747    SimObject::resume();
748    for (int x = 0;x < chan.size(); x++)
749        chan[x]->resume();
750}
751
752
753void
754CopyEngine::CopyEngineChannel::resume()
755{
756    DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
757    restartStateMachine();
758}
759
760CopyEngine *
761CopyEngineParams::create()
762{
763    return new CopyEngine(this);
764}
765