dev: Move the CopyEngine class to src/dev/pci
authorAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 10 Dec 2015 10:35:16 +0000 (10:35 +0000)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 10 Dec 2015 10:35:16 +0000 (10:35 +0000)
--HG--
rename : src/dev/CopyEngine.py => src/dev/pci/CopyEngine.py
rename : src/dev/copy_engine.cc => src/dev/pci/copy_engine.cc
rename : src/dev/copy_engine.hh => src/dev/pci/copy_engine.hh
rename : src/dev/copy_engine_defs.hh => src/dev/pci/copy_engine_defs.hh

src/dev/CopyEngine.py [deleted file]
src/dev/SConscript
src/dev/copy_engine.cc [deleted file]
src/dev/copy_engine.hh [deleted file]
src/dev/copy_engine_defs.hh [deleted file]
src/dev/pci/CopyEngine.py [new file with mode: 0644]
src/dev/pci/SConscript
src/dev/pci/copy_engine.cc [new file with mode: 0644]
src/dev/pci/copy_engine.hh [new file with mode: 0644]
src/dev/pci/copy_engine_defs.hh [new file with mode: 0644]

diff --git a/src/dev/CopyEngine.py b/src/dev/CopyEngine.py
deleted file mode 100644 (file)
index 2db9746..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (c) 2008 The Regents of The University of Michigan
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: Ali Saidi
-
-from m5.SimObject import SimObject
-from m5.params import *
-from m5.proxy import *
-from PciDevice import PciDevice
-
-class CopyEngine(PciDevice):
-    type = 'CopyEngine'
-    cxx_header = "dev/copy_engine.hh"
-    dma = VectorMasterPort("Copy engine DMA port")
-    VendorID = 0x8086
-    DeviceID = 0x1a38
-    Revision = 0xA2 # CM2 stepping (newest listed)
-    SubsystemID = 0
-    SubsystemVendorID = 0
-    Status = 0x0000
-    SubClassCode = 0x08
-    ClassCode = 0x80
-    ProgIF = 0x00
-    MaximumLatency = 0x00
-    MinimumGrant = 0xff
-    InterruptLine = 0x20
-    InterruptPin = 0x01
-    BAR0Size = '1kB'
-
-    ChanCnt = Param.UInt8(4, "Number of DMA channels that exist on device")
-    XferCap = Param.MemorySize('4kB', "Number of bits of transfer size that are supported")
-
-    latBeforeBegin = Param.Latency('20ns', "Latency after a DMA command is seen before it's proccessed")
-    latAfterCompletion = Param.Latency('20ns', "Latency after a DMA command is complete before it's reported as such")
-
-
index 9234170783ee62bd00f9d241b15da5890f033a1f..53bb284567344ab6e62cb7edb7bbf56094aeadda 100644 (file)
@@ -40,7 +40,6 @@ if env['TARGET_ISA'] == 'null':
     Return()
 
 SimObject('BadDevice.py')
-SimObject('CopyEngine.py')
 SimObject('DiskImage.py')
 SimObject('Ethernet.py')
 SimObject('I2C.py')
@@ -51,7 +50,6 @@ SimObject('Terminal.py')
 SimObject('Uart.py')
 
 Source('baddev.cc')
-Source('copy_engine.cc')
 Source('disk_image.cc')
 Source('dma_device.cc')
 Source('etherbus.cc')
@@ -85,7 +83,6 @@ Source('uart8250.cc')
 DebugFlag('DiskImageRead')
 DebugFlag('DiskImageWrite')
 DebugFlag('DMA')
-DebugFlag('DMACopyEngine')
 DebugFlag('Ethernet')
 DebugFlag('MultiEthernet')
 DebugFlag('MultiEthernetPkt')
diff --git a/src/dev/copy_engine.cc b/src/dev/copy_engine.cc
deleted file mode 100644 (file)
index dfeaf12..0000000
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * Copyright (c) 2012 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2008 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/* @file
- * Device model for Intel's I/O AT DMA copy engine.
- */
-
-#include <algorithm>
-
-#include "base/cp_annotate.hh"
-#include "base/trace.hh"
-#include "debug/DMACopyEngine.hh"
-#include "debug/Drain.hh"
-#include "dev/copy_engine.hh"
-#include "mem/packet.hh"
-#include "mem/packet_access.hh"
-#include "params/CopyEngine.hh"
-#include "sim/stats.hh"
-#include "sim/system.hh"
-
-using namespace CopyEngineReg;
-
-CopyEngine::CopyEngine(const Params *p)
-    : PciDevice(p)
-{
-    // All Reg regs are initialized to 0 by default
-    regs.chanCount = p->ChanCnt;
-    regs.xferCap = findMsbSet(p->XferCap);
-    regs.attnStatus = 0;
-
-    if (regs.chanCount > 64)
-        fatal("CopyEngine interface doesn't support more than 64 DMA engines\n");
-
-    for (int x = 0; x < regs.chanCount; x++) {
-        CopyEngineChannel *ch = new CopyEngineChannel(this, x);
-        chan.push_back(ch);
-    }
-}
-
-
-CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
-    : cePort(_ce, _ce->sys),
-      ce(_ce), channelId(cid), busy(false), underReset(false),
-    refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
-    latAfterCompletion(ce->params()->latAfterCompletion),
-    completionDataReg(0), nextState(Idle),
-    fetchCompleteEvent(this), addrCompleteEvent(this),
-    readCompleteEvent(this), writeCompleteEvent(this),
-    statusCompleteEvent(this)
-
-{
-        cr.status.dma_transfer_status(3);
-        cr.descChainAddr = 0;
-        cr.completionAddr = 0;
-
-        curDmaDesc = new DmaDesc;
-        memset(curDmaDesc, 0, sizeof(DmaDesc));
-        copyBuffer = new uint8_t[ce->params()->XferCap];
-}
-
-CopyEngine::~CopyEngine()
-{
-    for (int x = 0; x < chan.size(); x++) {
-        delete chan[x];
-    }
-}
-
-CopyEngine::CopyEngineChannel::~CopyEngineChannel()
-{
-    delete curDmaDesc;
-    delete [] copyBuffer;
-}
-
-BaseMasterPort &
-CopyEngine::getMasterPort(const std::string &if_name, PortID idx)
-{
-    if (if_name != "dma") {
-        // pass it along to our super class
-        return PciDevice::getMasterPort(if_name, idx);
-    } else {
-        if (idx >= static_cast<int>(chan.size())) {
-            panic("CopyEngine::getMasterPort: unknown index %d\n", idx);
-        }
-
-        return chan[idx]->getMasterPort();
-    }
-}
-
-
-BaseMasterPort &
-CopyEngine::CopyEngineChannel::getMasterPort()
-{
-    return cePort;
-}
-
-void
-CopyEngine::CopyEngineChannel::recvCommand()
-{
-    if (cr.command.start_dma()) {
-        assert(!busy);
-        cr.status.dma_transfer_status(0);
-        nextState = DescriptorFetch;
-        fetchAddress = cr.descChainAddr;
-        if (ce->drainState() == DrainState::Running)
-            fetchDescriptor(cr.descChainAddr);
-    } else if (cr.command.append_dma()) {
-        if (!busy) {
-            nextState = AddressFetch;
-            if (ce->drainState() == DrainState::Running)
-                fetchNextAddr(lastDescriptorAddr);
-        } else
-            refreshNext = true;
-    } else if (cr.command.reset_dma()) {
-        if (busy)
-            underReset = true;
-        else {
-            cr.status.dma_transfer_status(3);
-            nextState = Idle;
-        }
-    } else if (cr.command.resume_dma() || cr.command.abort_dma() ||
-            cr.command.suspend_dma())
-        panic("Resume, Abort, and Suspend are not supported\n");
-    cr.command(0);
-}
-
-Tick
-CopyEngine::read(PacketPtr pkt)
-{
-    int bar;
-    Addr daddr;
-
-    if (!getBAR(pkt->getAddr(), bar, daddr))
-        panic("Invalid PCI memory access to unmapped memory.\n");
-
-    // Only Memory register BAR is allowed
-    assert(bar == 0);
-
-    int size = pkt->getSize();
-    if (size != sizeof(uint64_t) && size != sizeof(uint32_t) &&
-        size != sizeof(uint16_t) && size != sizeof(uint8_t)) {
-        panic("Unknown size for MMIO access: %d\n", pkt->getSize());
-    }
-
-    DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size);
-
-    ///
-    /// Handle read of register here
-    ///
-
-    if (daddr < 0x80) {
-        switch (daddr) {
-          case GEN_CHANCOUNT:
-            assert(size == sizeof(regs.chanCount));
-            pkt->set<uint8_t>(regs.chanCount);
-            break;
-          case GEN_XFERCAP:
-            assert(size == sizeof(regs.xferCap));
-            pkt->set<uint8_t>(regs.xferCap);
-            break;
-          case GEN_INTRCTRL:
-            assert(size == sizeof(uint8_t));
-            pkt->set<uint8_t>(regs.intrctrl());
-            regs.intrctrl.master_int_enable(0);
-            break;
-          case GEN_ATTNSTATUS:
-            assert(size == sizeof(regs.attnStatus));
-            pkt->set<uint32_t>(regs.attnStatus);
-            regs.attnStatus = 0;
-            break;
-          default:
-            panic("Read request to unknown register number: %#x\n", daddr);
-        }
-        pkt->makeAtomicResponse();
-        return pioDelay;
-    }
-
-
-    // Find which channel we're accessing
-    int chanid = 0;
-    daddr -= 0x80;
-    while (daddr >= 0x80) {
-        chanid++;
-        daddr -= 0x80;
-    }
-
-    if (chanid >= regs.chanCount)
-        panic("Access to channel %d (device only configured for %d channels)",
-                chanid, regs.chanCount);
-
-    ///
-    /// Channel registers are handled here
-    ///
-    chan[chanid]->channelRead(pkt, daddr, size);
-
-    pkt->makeAtomicResponse();
-    return pioDelay;
-}
-
-void
-CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size)
-{
-    switch (daddr) {
-      case CHAN_CONTROL:
-        assert(size == sizeof(uint16_t));
-        pkt->set<uint16_t>(cr.ctrl());
-        cr.ctrl.in_use(1);
-        break;
-      case CHAN_STATUS:
-        assert(size == sizeof(uint64_t));
-        pkt->set<uint64_t>(cr.status() | ~busy);
-        break;
-      case CHAN_CHAINADDR:
-        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
-        if (size == sizeof(uint64_t))
-            pkt->set<uint64_t>(cr.descChainAddr);
-        else
-            pkt->set<uint32_t>(bits(cr.descChainAddr,0,31));
-        break;
-      case CHAN_CHAINADDR_HIGH:
-        assert(size == sizeof(uint32_t));
-        pkt->set<uint32_t>(bits(cr.descChainAddr,32,63));
-        break;
-      case CHAN_COMMAND:
-        assert(size == sizeof(uint8_t));
-        pkt->set<uint32_t>(cr.command());
-        break;
-      case CHAN_CMPLNADDR:
-        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
-        if (size == sizeof(uint64_t))
-            pkt->set<uint64_t>(cr.completionAddr);
-        else
-            pkt->set<uint32_t>(bits(cr.completionAddr,0,31));
-        break;
-      case CHAN_CMPLNADDR_HIGH:
-        assert(size == sizeof(uint32_t));
-        pkt->set<uint32_t>(bits(cr.completionAddr,32,63));
-        break;
-      case CHAN_ERROR:
-        assert(size == sizeof(uint32_t));
-        pkt->set<uint32_t>(cr.error());
-        break;
-      default:
-        panic("Read request to unknown channel register number: (%d)%#x\n",
-                channelId, daddr);
-    }
-}
-
-
-Tick
-CopyEngine::write(PacketPtr pkt)
-{
-    int bar;
-    Addr daddr;
-
-
-    if (!getBAR(pkt->getAddr(), bar, daddr))
-        panic("Invalid PCI memory access to unmapped memory.\n");
-
-    // Only Memory register BAR is allowed
-    assert(bar == 0);
-
-    int size = pkt->getSize();
-
-    ///
-    /// Handle write of register here
-    ///
-
-    if (size == sizeof(uint64_t)) {
-        uint64_t val M5_VAR_USED = pkt->get<uint64_t>();
-        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
-    } else if (size == sizeof(uint32_t)) {
-        uint32_t val M5_VAR_USED = pkt->get<uint32_t>();
-        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
-    } else if (size == sizeof(uint16_t)) {
-        uint16_t val M5_VAR_USED = pkt->get<uint16_t>();
-        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
-    } else if (size == sizeof(uint8_t)) {
-        uint8_t val M5_VAR_USED = pkt->get<uint8_t>();
-        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
-    } else {
-        panic("Unknown size for MMIO access: %d\n", size);
-    }
-
-    if (daddr < 0x80) {
-        switch (daddr) {
-          case GEN_CHANCOUNT:
-          case GEN_XFERCAP:
-          case GEN_ATTNSTATUS:
-            DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
-                    daddr);
-            break;
-          case GEN_INTRCTRL:
-            regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1));
-            break;
-          default:
-            panic("Read request to unknown register number: %#x\n", daddr);
-        }
-        pkt->makeAtomicResponse();
-        return pioDelay;
-    }
-
-    // Find which channel we're accessing
-    int chanid = 0;
-    daddr -= 0x80;
-    while (daddr >= 0x80) {
-        chanid++;
-        daddr -= 0x80;
-    }
-
-    if (chanid >= regs.chanCount)
-        panic("Access to channel %d (device only configured for %d channels)",
-                chanid, regs.chanCount);
-
-    ///
-    /// Channel registers are handled here
-    ///
-    chan[chanid]->channelWrite(pkt, daddr, size);
-
-    pkt->makeAtomicResponse();
-    return pioDelay;
-}
-
-void
-CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size)
-{
-    switch (daddr) {
-      case CHAN_CONTROL:
-        assert(size == sizeof(uint16_t));
-        int old_int_disable;
-        old_int_disable = cr.ctrl.interrupt_disable();
-        cr.ctrl(pkt->get<uint16_t>());
-        if (cr.ctrl.interrupt_disable())
-            cr.ctrl.interrupt_disable(0);
-        else
-            cr.ctrl.interrupt_disable(old_int_disable);
-        break;
-      case CHAN_STATUS:
-        assert(size == sizeof(uint64_t));
-        DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
-                    daddr);
-        break;
-      case CHAN_CHAINADDR:
-        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
-        if (size == sizeof(uint64_t))
-            cr.descChainAddr = pkt->get<uint64_t>();
-        else
-            cr.descChainAddr =  (uint64_t)pkt->get<uint32_t>() |
-                (cr.descChainAddr & ~mask(32));
-        DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
-        break;
-      case CHAN_CHAINADDR_HIGH:
-        assert(size == sizeof(uint32_t));
-        cr.descChainAddr =  ((uint64_t)pkt->get<uint32_t>() <<32) |
-            (cr.descChainAddr & mask(32));
-        DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
-        break;
-      case CHAN_COMMAND:
-        assert(size == sizeof(uint8_t));
-        cr.command(pkt->get<uint8_t>());
-        recvCommand();
-        break;
-      case CHAN_CMPLNADDR:
-        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
-        if (size == sizeof(uint64_t))
-            cr.completionAddr = pkt->get<uint64_t>();
-        else
-            cr.completionAddr =  pkt->get<uint32_t>() |
-                (cr.completionAddr & ~mask(32));
-        break;
-      case CHAN_CMPLNADDR_HIGH:
-        assert(size == sizeof(uint32_t));
-        cr.completionAddr =  ((uint64_t)pkt->get<uint32_t>() <<32) |
-            (cr.completionAddr & mask(32));
-        break;
-      case CHAN_ERROR:
-        assert(size == sizeof(uint32_t));
-        cr.error(~pkt->get<uint32_t>() & cr.error());
-        break;
-      default:
-        panic("Read request to unknown channel register number: (%d)%#x\n",
-                channelId, daddr);
-    }
-}
-
-void
-CopyEngine::regStats()
-{
-    using namespace Stats;
-    bytesCopied
-        .init(regs.chanCount)
-        .name(name() + ".bytes_copied")
-        .desc("Number of bytes copied by each engine")
-        .flags(total)
-        ;
-    copiesProcessed
-        .init(regs.chanCount)
-        .name(name() + ".copies_processed")
-        .desc("Number of copies processed by each engine")
-        .flags(total)
-        ;
-}
-
-void
-CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address)
-{
-    anDq();
-    anBegin("FetchDescriptor");
-    DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n",
-           address, ce->pciToDma(address));
-    assert(address);
-    busy = true;
-
-    DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n",
-            ce->pciToDma(address), sizeof(DmaDesc), curDmaDesc);
-
-    cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(address),
-                     sizeof(DmaDesc), &fetchCompleteEvent,
-                     (uint8_t*)curDmaDesc, latBeforeBegin);
-    lastDescriptorAddr = address;
-}
-
-void
-CopyEngine::CopyEngineChannel::fetchDescComplete()
-{
-    DPRINTF(DMACopyEngine, "Read of descriptor complete\n");
-
-    if ((curDmaDesc->command & DESC_CTRL_NULL)) {
-        DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n");
-        assert(!(curDmaDesc->command & DESC_CTRL_CP_STS));
-        if (curDmaDesc->command & DESC_CTRL_CP_STS) {
-            panic("Shouldn't be able to get here\n");
-            nextState = CompletionWrite;
-            if (inDrain()) return;
-            writeCompletionStatus();
-        } else {
-            anBegin("Idle");
-            anWait();
-            busy = false;
-            nextState = Idle;
-            inDrain();
-        }
-        return;
-    }
-
-    if (curDmaDesc->command & ~DESC_CTRL_CP_STS)
-        panic("Descriptor has flag other that completion status set\n");
-
-    nextState = DMARead;
-    if (inDrain()) return;
-    readCopyBytes();
-}
-
-void
-CopyEngine::CopyEngineChannel::readCopyBytes()
-{
-    anBegin("ReadCopyBytes");
-    DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n",
-           curDmaDesc->len, curDmaDesc->dest,
-           ce->pciToDma(curDmaDesc->src));
-    cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(curDmaDesc->src),
-                     curDmaDesc->len, &readCompleteEvent, copyBuffer, 0);
-}
-
-void
-CopyEngine::CopyEngineChannel::readCopyBytesComplete()
-{
-    DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n");
-
-    nextState = DMAWrite;
-    if (inDrain()) return;
-    writeCopyBytes();
-}
-
-void
-CopyEngine::CopyEngineChannel::writeCopyBytes()
-{
-    anBegin("WriteCopyBytes");
-    DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n",
-           curDmaDesc->len, curDmaDesc->dest,
-           ce->pciToDma(curDmaDesc->dest));
-
-    cePort.dmaAction(MemCmd::WriteReq, ce->pciToDma(curDmaDesc->dest),
-                     curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0);
-
-    ce->bytesCopied[channelId] += curDmaDesc->len;
-    ce->copiesProcessed[channelId]++;
-}
-
-void
-CopyEngine::CopyEngineChannel::writeCopyBytesComplete()
-{
-    DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n",
-            curDmaDesc->user1);
-
-    cr.status.compl_desc_addr(lastDescriptorAddr >> 6);
-    completionDataReg = cr.status() | 1;
-
-    anQ("DMAUsedDescQ", channelId, 1);
-    anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len);
-    if (curDmaDesc->command & DESC_CTRL_CP_STS) {
-        nextState = CompletionWrite;
-        if (inDrain()) return;
-        writeCompletionStatus();
-        return;
-    }
-
-    continueProcessing();
-}
-
-void
-CopyEngine::CopyEngineChannel::continueProcessing()
-{
-    busy = false;
-
-    if (underReset) {
-        anBegin("Reset");
-        anWait();
-        underReset = false;
-        refreshNext = false;
-        busy = false;
-        nextState = Idle;
-        return;
-    }
-
-    if (curDmaDesc->next) {
-        nextState = DescriptorFetch;
-        fetchAddress = curDmaDesc->next;
-        if (inDrain()) return;
-        fetchDescriptor(curDmaDesc->next);
-    } else if (refreshNext) {
-        nextState = AddressFetch;
-        refreshNext = false;
-        if (inDrain()) return;
-        fetchNextAddr(lastDescriptorAddr);
-    } else {
-        inDrain();
-        nextState = Idle;
-        anWait();
-        anBegin("Idle");
-    }
-}
-
-void
-CopyEngine::CopyEngineChannel::writeCompletionStatus()
-{
-    anBegin("WriteCompletionStatus");
-    DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n",
-            completionDataReg, cr.completionAddr,
-            ce->pciToDma(cr.completionAddr));
-
-    cePort.dmaAction(MemCmd::WriteReq,
-                     ce->pciToDma(cr.completionAddr),
-                     sizeof(completionDataReg), &statusCompleteEvent,
-                     (uint8_t*)&completionDataReg, latAfterCompletion);
-}
-
-void
-CopyEngine::CopyEngineChannel::writeStatusComplete()
-{
-    DPRINTF(DMACopyEngine, "Writing completion status complete\n");
-    continueProcessing();
-}
-
-void
-CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address)
-{
-    anBegin("FetchNextAddr");
-    DPRINTF(DMACopyEngine, "Fetching next address...\n");
-    busy = true;
-    cePort.dmaAction(MemCmd::ReadReq,
-                     ce->pciToDma(address + offsetof(DmaDesc, next)),
-                     sizeof(Addr), &addrCompleteEvent,
-                     (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0);
-}
-
-void
-CopyEngine::CopyEngineChannel::fetchAddrComplete()
-{
-    DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n",
-            curDmaDesc->next);
-    if (!curDmaDesc->next) {
-        DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n");
-        busy = false;
-        nextState = Idle;
-        anWait();
-        anBegin("Idle");
-        inDrain();
-        return;
-    }
-    nextState = DescriptorFetch;
-    fetchAddress = curDmaDesc->next;
-    if (inDrain()) return;
-    fetchDescriptor(curDmaDesc->next);
-}
-
-bool
-CopyEngine::CopyEngineChannel::inDrain()
-{
-    if (drainState() == DrainState::Draining) {
-        DPRINTF(Drain, "CopyEngine done draining, processing drain event\n");
-        signalDrainDone();
-    }
-
-    return ce->drainState() != DrainState::Running;
-}
-
-DrainState
-CopyEngine::CopyEngineChannel::drain()
-{
-    if (nextState == Idle || ce->drainState() != DrainState::Running) {
-        return DrainState::Drained;
-    } else {
-        DPRINTF(Drain, "CopyEngineChannel not drained\n");
-        return DrainState::Draining;
-    }
-}
-
-void
-CopyEngine::serialize(CheckpointOut &cp) const
-{
-    PciDevice::serialize(cp);
-    regs.serialize(cp);
-    for (int x =0; x < chan.size(); x++)
-        chan[x]->serializeSection(cp, csprintf("channel%d", x));
-}
-
-void
-CopyEngine::unserialize(CheckpointIn &cp)
-{
-    PciDevice::unserialize(cp);
-    regs.unserialize(cp);
-    for (int x = 0; x < chan.size(); x++)
-        chan[x]->unserializeSection(cp, csprintf("channel%d", x));
-}
-
-void
-CopyEngine::CopyEngineChannel::serialize(CheckpointOut &cp) const
-{
-    SERIALIZE_SCALAR(channelId);
-    SERIALIZE_SCALAR(busy);
-    SERIALIZE_SCALAR(underReset);
-    SERIALIZE_SCALAR(refreshNext);
-    SERIALIZE_SCALAR(lastDescriptorAddr);
-    SERIALIZE_SCALAR(completionDataReg);
-    SERIALIZE_SCALAR(fetchAddress);
-    int nextState = this->nextState;
-    SERIALIZE_SCALAR(nextState);
-    arrayParamOut(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
-    SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
-    cr.serialize(cp);
-
-}
-void
-CopyEngine::CopyEngineChannel::unserialize(CheckpointIn &cp)
-{
-    UNSERIALIZE_SCALAR(channelId);
-    UNSERIALIZE_SCALAR(busy);
-    UNSERIALIZE_SCALAR(underReset);
-    UNSERIALIZE_SCALAR(refreshNext);
-    UNSERIALIZE_SCALAR(lastDescriptorAddr);
-    UNSERIALIZE_SCALAR(completionDataReg);
-    UNSERIALIZE_SCALAR(fetchAddress);
-    int nextState;
-    UNSERIALIZE_SCALAR(nextState);
-    this->nextState = (ChannelState)nextState;
-    arrayParamIn(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
-    UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
-    cr.unserialize(cp);
-
-}
-
-void
-CopyEngine::CopyEngineChannel::restartStateMachine()
-{
-    switch(nextState) {
-      case AddressFetch:
-        fetchNextAddr(lastDescriptorAddr);
-        break;
-      case DescriptorFetch:
-        fetchDescriptor(fetchAddress);
-        break;
-      case DMARead:
-        readCopyBytes();
-        break;
-      case DMAWrite:
-        writeCopyBytes();
-        break;
-      case CompletionWrite:
-        writeCompletionStatus();
-        break;
-      case Idle:
-        break;
-      default:
-        panic("Unknown state for CopyEngineChannel\n");
-    }
-}
-
-void
-CopyEngine::CopyEngineChannel::drainResume()
-{
-    DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
-    restartStateMachine();
-}
-
-CopyEngine *
-CopyEngineParams::create()
-{
-    return new CopyEngine(this);
-}
diff --git a/src/dev/copy_engine.hh b/src/dev/copy_engine.hh
deleted file mode 100644 (file)
index 754ea5e..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (c) 2012 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2008 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/* @file
- * Device model for Intel's I/O Acceleration Technology (I/OAT).
- * A DMA asyncronous copy engine
- */
-
-#ifndef __DEV_COPY_ENGINE_HH__
-#define __DEV_COPY_ENGINE_HH__
-
-#include <vector>
-
-#include "base/cp_annotate.hh"
-#include "base/statistics.hh"
-#include "dev/copy_engine_defs.hh"
-#include "dev/pci/device.hh"
-#include "params/CopyEngine.hh"
-#include "sim/drain.hh"
-#include "sim/eventq.hh"
-
-class CopyEngine : public PciDevice
-{
-    class CopyEngineChannel : public Drainable, public Serializable
-    {
-      private:
-        DmaPort cePort;
-        CopyEngine *ce;
-        CopyEngineReg::ChanRegs  cr;
-        int channelId;
-        CopyEngineReg::DmaDesc *curDmaDesc;
-        uint8_t *copyBuffer;
-
-        bool busy;
-        bool underReset;
-        bool refreshNext;
-        Addr lastDescriptorAddr;
-        Addr fetchAddress;
-
-        Tick latBeforeBegin;
-        Tick latAfterCompletion;
-
-        uint64_t completionDataReg;
-
-        enum ChannelState {
-            Idle,
-            AddressFetch,
-            DescriptorFetch,
-            DMARead,
-            DMAWrite,
-            CompletionWrite
-        };
-
-        ChannelState nextState;
-
-      public:
-        CopyEngineChannel(CopyEngine *_ce, int cid);
-        virtual ~CopyEngineChannel();
-        BaseMasterPort &getMasterPort();
-
-        std::string name() { assert(ce); return ce->name() + csprintf("-chan%d", channelId); }
-        virtual Tick read(PacketPtr pkt)
-                        { panic("CopyEngineChannel has no I/O access\n");}
-        virtual Tick write(PacketPtr pkt)
-                        { panic("CopyEngineChannel has no I/O access\n"); }
-
-        void channelRead(PacketPtr pkt, Addr daddr, int size);
-        void channelWrite(PacketPtr pkt, Addr daddr, int size);
-
-        DrainState drain() override;
-        void drainResume() override;
-
-        void serialize(CheckpointOut &cp) const override;
-        void unserialize(CheckpointIn &cp) override;
-
-      private:
-        void fetchDescriptor(Addr address);
-        void fetchDescComplete();
-        EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchDescComplete>
-            fetchCompleteEvent;
-
-        void fetchNextAddr(Addr address);
-        void fetchAddrComplete();
-        EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchAddrComplete>
-            addrCompleteEvent;
-
-        void readCopyBytes();
-        void readCopyBytesComplete();
-        EventWrapper<CopyEngineChannel, &CopyEngineChannel::readCopyBytesComplete>
-            readCompleteEvent;
-
-        void writeCopyBytes();
-        void writeCopyBytesComplete();
-        EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeCopyBytesComplete>
-            writeCompleteEvent;
-
-        void writeCompletionStatus();
-        void writeStatusComplete();
-        EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeStatusComplete>
-            statusCompleteEvent;
-
-
-        void continueProcessing();
-        void recvCommand();
-        bool inDrain();
-        void restartStateMachine();
-        inline void anBegin(const char *s)
-        {
-            CPA::cpa()->hwBegin(CPA::FL_NONE, ce->sys,
-                         channelId, "CopyEngine", s);
-        }
-
-        inline void anWait()
-        {
-            CPA::cpa()->hwWe(CPA::FL_NONE, ce->sys,
-                     channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
-        }
-
-        inline void anDq()
-        {
-            CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys,
-                      channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
-        }
-
-        inline void anPq()
-        {
-            CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys,
-                      channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
-        }
-
-        inline void anQ(const char * s, uint64_t id, int size = 1)
-        {
-            CPA::cpa()->hwQ(CPA::FL_NONE, ce->sys, channelId,
-                    "CopyEngine", s, id, NULL, size);
-        }
-
-    };
-
-  private:
-
-    Stats::Vector bytesCopied;
-    Stats::Vector copiesProcessed;
-
-    // device registers
-    CopyEngineReg::Regs regs;
-
-    // Array of channels each one with regs/dma port/etc
-    std::vector<CopyEngineChannel*> chan;
-
-  public:
-    typedef CopyEngineParams Params;
-    const Params *
-    params() const
-    {
-        return dynamic_cast<const Params *>(_params);
-    }
-    CopyEngine(const Params *params);
-    ~CopyEngine();
-
-    void regStats() override;
-
-    BaseMasterPort &getMasterPort(const std::string &if_name,
-                                  PortID idx = InvalidPortID) override;
-
-    Tick read(PacketPtr pkt) override;
-    Tick write(PacketPtr pkt) override;
-
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
-};
-
-#endif //__DEV_COPY_ENGINE_HH__
-
diff --git a/src/dev/copy_engine_defs.hh b/src/dev/copy_engine_defs.hh
deleted file mode 100644 (file)
index 9a88802..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 2008 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/* @file
- * Register and structure descriptions for Intel's I/O AT DMA Engine
- */
-#include "base/bitfield.hh"
-#include "sim/serialize.hh"
-
-namespace CopyEngineReg {
-
-
-// General Channel independant registers, 128 bytes starting at 0x00
-const uint32_t GEN_CHANCOUNT    = 0x00;
-const uint32_t GEN_XFERCAP      = 0x01;
-const uint32_t GEN_INTRCTRL     = 0x03;
-const uint32_t GEN_ATTNSTATUS   = 0x04;
-
-
-// Channel specific registers, each block is 128 bytes, starting at 0x80
-const uint32_t CHAN_CONTROL         = 0x00;
-const uint32_t CHAN_STATUS          = 0x04;
-const uint32_t CHAN_CHAINADDR       = 0x0C;
-const uint32_t CHAN_CHAINADDR_LOW   = 0x0C;
-const uint32_t CHAN_CHAINADDR_HIGH  = 0x10;
-const uint32_t CHAN_COMMAND         = 0x14;
-const uint32_t CHAN_CMPLNADDR       = 0x18;
-const uint32_t CHAN_CMPLNADDR_LOW   = 0x18;
-const uint32_t CHAN_CMPLNADDR_HIGH  = 0x1C;
-const uint32_t CHAN_ERROR           = 0x28;
-
-
-const uint32_t DESC_CTRL_INT_GEN    = 0x00000001;
-const uint32_t DESC_CTRL_SRC_SN     = 0x00000002;
-const uint32_t DESC_CTRL_DST_SN     = 0x00000004;
-const uint32_t DESC_CTRL_CP_STS     = 0x00000008;
-const uint32_t DESC_CTRL_FRAME      = 0x00000010;
-const uint32_t DESC_CTRL_NULL       = 0x00000020;
-
-struct DmaDesc {
-    uint32_t len;
-    uint32_t command;
-    Addr src;
-    Addr dest;
-    Addr next;
-    uint64_t reserved1;
-    uint64_t reserved2;
-    uint64_t user1;
-    uint64_t user2;
-};
-
-#define ADD_FIELD8(NAME, OFFSET, BITS) \
-    inline uint8_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
-    inline void NAME(uint8_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
-
-#define ADD_FIELD16(NAME, OFFSET, BITS) \
-    inline uint16_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
-    inline void NAME(uint16_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
-
-#define ADD_FIELD32(NAME, OFFSET, BITS) \
-    inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
-    inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
-
-#define ADD_FIELD64(NAME, OFFSET, BITS) \
-    inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
-    inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
-
-template<class T>
-struct Reg {
-    T _data;
-    T operator()() { return _data; }
-    const Reg<T> &operator=(T d) { _data = d; return *this;}
-    bool operator==(T d) { return d == _data; }
-    void operator()(T d) { _data = d; }
-    Reg() { _data = 0; }
-    void serialize(CheckpointOut &cp) const
-    {
-        SERIALIZE_SCALAR(_data);
-    }
-    void unserialize(CheckpointIn &cp)
-    {
-        UNSERIALIZE_SCALAR(_data);
-    }
-};
-
-
-struct Regs : public Serializable {
-    uint8_t chanCount;
-    uint8_t xferCap;
-
-    struct INTRCTRL : public Reg<uint8_t> { // 0x03
-        using Reg<uint8_t>::operator =;
-        ADD_FIELD8(master_int_enable,0,1);
-        ADD_FIELD8(interrupt_status,1,1);
-        ADD_FIELD8(interrupt,2,1);
-    };
-    INTRCTRL intrctrl;
-
-    uint32_t attnStatus; // Read clears
-
-    void serialize(CheckpointOut &cp) const override
-    {
-        SERIALIZE_SCALAR(chanCount);
-        SERIALIZE_SCALAR(xferCap);
-        paramOut(cp, "intrctrl", intrctrl._data);
-        SERIALIZE_SCALAR(attnStatus);
-    }
-
-    void unserialize(CheckpointIn &cp) override
-    {
-        UNSERIALIZE_SCALAR(chanCount);
-        UNSERIALIZE_SCALAR(xferCap);
-        paramIn(cp, "intrctrl", intrctrl._data);
-        UNSERIALIZE_SCALAR(attnStatus);
-    }
-
-};
-
-struct ChanRegs : public Serializable {
-    struct CHANCTRL : public Reg<uint16_t> { // channelX + 0x00
-        using Reg<uint16_t>::operator =;
-        ADD_FIELD16(interrupt_disable,0,1);
-        ADD_FIELD16(error_completion_enable, 2,1);
-        ADD_FIELD16(any_error_abort_enable,3,1);
-        ADD_FIELD16(error_int_enable,4,1);
-        ADD_FIELD16(desc_addr_snoop_control,5,1);
-        ADD_FIELD16(in_use, 8,1);
-    };
-    CHANCTRL ctrl;
-
-    struct CHANSTS : public Reg<uint64_t> { // channelX + 0x04
-        ADD_FIELD64(dma_transfer_status, 0, 3);
-        ADD_FIELD64(unaffiliated_error, 3, 1);
-        ADD_FIELD64(soft_error, 4, 1);
-        ADD_FIELD64(compl_desc_addr, 6, 58);
-    };
-    CHANSTS status;
-
-    uint64_t descChainAddr;
-
-    struct CHANCMD : public Reg<uint8_t> { // channelX + 0x14
-        ADD_FIELD8(start_dma,0,1);
-        ADD_FIELD8(append_dma,1,1);
-        ADD_FIELD8(suspend_dma,2,1);
-        ADD_FIELD8(abort_dma,3,1);
-        ADD_FIELD8(resume_dma,4,1);
-        ADD_FIELD8(reset_dma,5,1);
-    };
-    CHANCMD command;
-
-    uint64_t completionAddr;
-
-    struct CHANERR : public Reg<uint32_t> { // channel X + 0x28
-        ADD_FIELD32(source_addr_error,0,1);
-        ADD_FIELD32(dest_addr_error,1,1);
-        ADD_FIELD32(ndesc_addr_error,2,1);
-        ADD_FIELD32(desc_error,3,1);
-        ADD_FIELD32(chain_addr_error,4,1);
-        ADD_FIELD32(chain_cmd_error,5,1);
-        ADD_FIELD32(chipset_parity_error,6,1);
-        ADD_FIELD32(dma_parity_error,7,1);
-        ADD_FIELD32(read_data_error,8,1);
-        ADD_FIELD32(write_data_error,9,1);
-        ADD_FIELD32(desc_control_error,10,1);
-        ADD_FIELD32(desc_len_error,11,1);
-        ADD_FIELD32(completion_addr_error,12,1);
-        ADD_FIELD32(interrupt_config_error,13,1);
-        ADD_FIELD32(soft_error,14,1);
-        ADD_FIELD32(unaffiliated_error,15,1);
-    };
-    CHANERR error;
-
-    void serialize(CheckpointOut &cp) const override
-    {
-        paramOut(cp, "ctrl", ctrl._data);
-        paramOut(cp, "status", status._data);
-        SERIALIZE_SCALAR(descChainAddr);
-        paramOut(cp, "command", command._data);
-        SERIALIZE_SCALAR(completionAddr);
-        paramOut(cp, "error", error._data);
-    }
-
-    void unserialize(CheckpointIn &cp) override
-    {
-        paramIn(cp, "ctrl", ctrl._data);
-        paramIn(cp, "status", status._data);
-        UNSERIALIZE_SCALAR(descChainAddr);
-        paramIn(cp, "command", command._data);
-        UNSERIALIZE_SCALAR(completionAddr);
-        paramIn(cp, "error", error._data);
-    }
-
-
-};
-
-} // namespace CopyEngineReg
-
-
diff --git a/src/dev/pci/CopyEngine.py b/src/dev/pci/CopyEngine.py
new file mode 100644 (file)
index 0000000..f1b9df1
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Ali Saidi
+
+from m5.SimObject import SimObject
+from m5.params import *
+from m5.proxy import *
+from PciDevice import PciDevice
+
+class CopyEngine(PciDevice):
+    type = 'CopyEngine'
+    cxx_header = "dev/pci/copy_engine.hh"
+    dma = VectorMasterPort("Copy engine DMA port")
+    VendorID = 0x8086
+    DeviceID = 0x1a38
+    Revision = 0xA2 # CM2 stepping (newest listed)
+    SubsystemID = 0
+    SubsystemVendorID = 0
+    Status = 0x0000
+    SubClassCode = 0x08
+    ClassCode = 0x80
+    ProgIF = 0x00
+    MaximumLatency = 0x00
+    MinimumGrant = 0xff
+    InterruptLine = 0x20
+    InterruptPin = 0x01
+    BAR0Size = '1kB'
+
+    ChanCnt = Param.UInt8(4, "Number of DMA channels that exist on device")
+    XferCap = Param.MemorySize('4kB', "Number of bits of transfer size that are supported")
+
+    latBeforeBegin = Param.Latency('20ns', "Latency after a DMA command is seen before it's proccessed")
+    latAfterCompletion = Param.Latency('20ns', "Latency after a DMA command is complete before it's reported as such")
+
+
index 14214424bd01aa70535e0f4064bf2a08a98dbfe7..2c48403f85448600fe1002e51c6fe50303817ea2 100644 (file)
@@ -55,3 +55,6 @@ SimObject('PciHost.py')
 Source('host.cc')
 DebugFlag('PciHost')
 
+SimObject('CopyEngine.py')
+Source('copy_engine.cc')
+DebugFlag('DMACopyEngine')
diff --git a/src/dev/pci/copy_engine.cc b/src/dev/pci/copy_engine.cc
new file mode 100644 (file)
index 0000000..fba96a1
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/* @file
+ * Device model for Intel's I/O AT DMA copy engine.
+ */
+
+#include "dev/pci/copy_engine.hh"
+
+#include <algorithm>
+
+#include "base/cp_annotate.hh"
+#include "base/trace.hh"
+#include "debug/DMACopyEngine.hh"
+#include "debug/Drain.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "params/CopyEngine.hh"
+#include "sim/stats.hh"
+#include "sim/system.hh"
+
+using namespace CopyEngineReg;
+
+CopyEngine::CopyEngine(const Params *p)
+    : PciDevice(p)
+{
+    // All Reg regs are initialized to 0 by default
+    regs.chanCount = p->ChanCnt;
+    regs.xferCap = findMsbSet(p->XferCap);
+    regs.attnStatus = 0;
+
+    if (regs.chanCount > 64)
+        fatal("CopyEngine interface doesn't support more than 64 DMA engines\n");
+
+    for (int x = 0; x < regs.chanCount; x++) {
+        CopyEngineChannel *ch = new CopyEngineChannel(this, x);
+        chan.push_back(ch);
+    }
+}
+
+
+CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
+    : cePort(_ce, _ce->sys),
+      ce(_ce), channelId(cid), busy(false), underReset(false),
+    refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
+    latAfterCompletion(ce->params()->latAfterCompletion),
+    completionDataReg(0), nextState(Idle),
+    fetchCompleteEvent(this), addrCompleteEvent(this),
+    readCompleteEvent(this), writeCompleteEvent(this),
+    statusCompleteEvent(this)
+
+{
+        cr.status.dma_transfer_status(3);
+        cr.descChainAddr = 0;
+        cr.completionAddr = 0;
+
+        curDmaDesc = new DmaDesc;
+        memset(curDmaDesc, 0, sizeof(DmaDesc));
+        copyBuffer = new uint8_t[ce->params()->XferCap];
+}
+
+CopyEngine::~CopyEngine()
+{
+    for (int x = 0; x < chan.size(); x++) {
+        delete chan[x];
+    }
+}
+
+CopyEngine::CopyEngineChannel::~CopyEngineChannel()
+{
+    delete curDmaDesc;
+    delete [] copyBuffer;
+}
+
+BaseMasterPort &
+CopyEngine::getMasterPort(const std::string &if_name, PortID idx)
+{
+    if (if_name != "dma") {
+        // pass it along to our super class
+        return PciDevice::getMasterPort(if_name, idx);
+    } else {
+        if (idx >= static_cast<int>(chan.size())) {
+            panic("CopyEngine::getMasterPort: unknown index %d\n", idx);
+        }
+
+        return chan[idx]->getMasterPort();
+    }
+}
+
+
+BaseMasterPort &
+CopyEngine::CopyEngineChannel::getMasterPort()
+{
+    return cePort;
+}
+
+void
+CopyEngine::CopyEngineChannel::recvCommand()
+{
+    if (cr.command.start_dma()) {
+        assert(!busy);
+        cr.status.dma_transfer_status(0);
+        nextState = DescriptorFetch;
+        fetchAddress = cr.descChainAddr;
+        if (ce->drainState() == DrainState::Running)
+            fetchDescriptor(cr.descChainAddr);
+    } else if (cr.command.append_dma()) {
+        if (!busy) {
+            nextState = AddressFetch;
+            if (ce->drainState() == DrainState::Running)
+                fetchNextAddr(lastDescriptorAddr);
+        } else
+            refreshNext = true;
+    } else if (cr.command.reset_dma()) {
+        if (busy)
+            underReset = true;
+        else {
+            cr.status.dma_transfer_status(3);
+            nextState = Idle;
+        }
+    } else if (cr.command.resume_dma() || cr.command.abort_dma() ||
+            cr.command.suspend_dma())
+        panic("Resume, Abort, and Suspend are not supported\n");
+    cr.command(0);
+}
+
+Tick
+CopyEngine::read(PacketPtr pkt)
+{
+    int bar;
+    Addr daddr;
+
+    if (!getBAR(pkt->getAddr(), bar, daddr))
+        panic("Invalid PCI memory access to unmapped memory.\n");
+
+    // Only Memory register BAR is allowed
+    assert(bar == 0);
+
+    int size = pkt->getSize();
+    if (size != sizeof(uint64_t) && size != sizeof(uint32_t) &&
+        size != sizeof(uint16_t) && size != sizeof(uint8_t)) {
+        panic("Unknown size for MMIO access: %d\n", pkt->getSize());
+    }
+
+    DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size);
+
+    ///
+    /// Handle read of register here
+    ///
+
+    if (daddr < 0x80) {
+        switch (daddr) {
+          case GEN_CHANCOUNT:
+            assert(size == sizeof(regs.chanCount));
+            pkt->set<uint8_t>(regs.chanCount);
+            break;
+          case GEN_XFERCAP:
+            assert(size == sizeof(regs.xferCap));
+            pkt->set<uint8_t>(regs.xferCap);
+            break;
+          case GEN_INTRCTRL:
+            assert(size == sizeof(uint8_t));
+            pkt->set<uint8_t>(regs.intrctrl());
+            regs.intrctrl.master_int_enable(0);
+            break;
+          case GEN_ATTNSTATUS:
+            assert(size == sizeof(regs.attnStatus));
+            pkt->set<uint32_t>(regs.attnStatus);
+            regs.attnStatus = 0;
+            break;
+          default:
+            panic("Read request to unknown register number: %#x\n", daddr);
+        }
+        pkt->makeAtomicResponse();
+        return pioDelay;
+    }
+
+
+    // Find which channel we're accessing
+    int chanid = 0;
+    daddr -= 0x80;
+    while (daddr >= 0x80) {
+        chanid++;
+        daddr -= 0x80;
+    }
+
+    if (chanid >= regs.chanCount)
+        panic("Access to channel %d (device only configured for %d channels)",
+                chanid, regs.chanCount);
+
+    ///
+    /// Channel registers are handled here
+    ///
+    chan[chanid]->channelRead(pkt, daddr, size);
+
+    pkt->makeAtomicResponse();
+    return pioDelay;
+}
+
+void
+CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size)
+{
+    switch (daddr) {
+      case CHAN_CONTROL:
+        assert(size == sizeof(uint16_t));
+        pkt->set<uint16_t>(cr.ctrl());
+        cr.ctrl.in_use(1);
+        break;
+      case CHAN_STATUS:
+        assert(size == sizeof(uint64_t));
+        pkt->set<uint64_t>(cr.status() | ~busy);
+        break;
+      case CHAN_CHAINADDR:
+        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
+        if (size == sizeof(uint64_t))
+            pkt->set<uint64_t>(cr.descChainAddr);
+        else
+            pkt->set<uint32_t>(bits(cr.descChainAddr,0,31));
+        break;
+      case CHAN_CHAINADDR_HIGH:
+        assert(size == sizeof(uint32_t));
+        pkt->set<uint32_t>(bits(cr.descChainAddr,32,63));
+        break;
+      case CHAN_COMMAND:
+        assert(size == sizeof(uint8_t));
+        pkt->set<uint32_t>(cr.command());
+        break;
+      case CHAN_CMPLNADDR:
+        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
+        if (size == sizeof(uint64_t))
+            pkt->set<uint64_t>(cr.completionAddr);
+        else
+            pkt->set<uint32_t>(bits(cr.completionAddr,0,31));
+        break;
+      case CHAN_CMPLNADDR_HIGH:
+        assert(size == sizeof(uint32_t));
+        pkt->set<uint32_t>(bits(cr.completionAddr,32,63));
+        break;
+      case CHAN_ERROR:
+        assert(size == sizeof(uint32_t));
+        pkt->set<uint32_t>(cr.error());
+        break;
+      default:
+        panic("Read request to unknown channel register number: (%d)%#x\n",
+                channelId, daddr);
+    }
+}
+
+
+Tick
+CopyEngine::write(PacketPtr pkt)
+{
+    int bar;
+    Addr daddr;
+
+
+    if (!getBAR(pkt->getAddr(), bar, daddr))
+        panic("Invalid PCI memory access to unmapped memory.\n");
+
+    // Only Memory register BAR is allowed
+    assert(bar == 0);
+
+    int size = pkt->getSize();
+
+    ///
+    /// Handle write of register here
+    ///
+
+    if (size == sizeof(uint64_t)) {
+        uint64_t val M5_VAR_USED = pkt->get<uint64_t>();
+        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
+    } else if (size == sizeof(uint32_t)) {
+        uint32_t val M5_VAR_USED = pkt->get<uint32_t>();
+        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
+    } else if (size == sizeof(uint16_t)) {
+        uint16_t val M5_VAR_USED = pkt->get<uint16_t>();
+        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
+    } else if (size == sizeof(uint8_t)) {
+        uint8_t val M5_VAR_USED = pkt->get<uint8_t>();
+        DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
+    } else {
+        panic("Unknown size for MMIO access: %d\n", size);
+    }
+
+    if (daddr < 0x80) {
+        switch (daddr) {
+          case GEN_CHANCOUNT:
+          case GEN_XFERCAP:
+          case GEN_ATTNSTATUS:
+            DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
+                    daddr);
+            break;
+          case GEN_INTRCTRL:
+            regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1));
+            break;
+          default:
+            panic("Read request to unknown register number: %#x\n", daddr);
+        }
+        pkt->makeAtomicResponse();
+        return pioDelay;
+    }
+
+    // Find which channel we're accessing
+    int chanid = 0;
+    daddr -= 0x80;
+    while (daddr >= 0x80) {
+        chanid++;
+        daddr -= 0x80;
+    }
+
+    if (chanid >= regs.chanCount)
+        panic("Access to channel %d (device only configured for %d channels)",
+                chanid, regs.chanCount);
+
+    ///
+    /// Channel registers are handled here
+    ///
+    chan[chanid]->channelWrite(pkt, daddr, size);
+
+    pkt->makeAtomicResponse();
+    return pioDelay;
+}
+
+void
+CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size)
+{
+    switch (daddr) {
+      case CHAN_CONTROL:
+        assert(size == sizeof(uint16_t));
+        int old_int_disable;
+        old_int_disable = cr.ctrl.interrupt_disable();
+        cr.ctrl(pkt->get<uint16_t>());
+        if (cr.ctrl.interrupt_disable())
+            cr.ctrl.interrupt_disable(0);
+        else
+            cr.ctrl.interrupt_disable(old_int_disable);
+        break;
+      case CHAN_STATUS:
+        assert(size == sizeof(uint64_t));
+        DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
+                    daddr);
+        break;
+      case CHAN_CHAINADDR:
+        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
+        if (size == sizeof(uint64_t))
+            cr.descChainAddr = pkt->get<uint64_t>();
+        else
+            cr.descChainAddr =  (uint64_t)pkt->get<uint32_t>() |
+                (cr.descChainAddr & ~mask(32));
+        DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
+        break;
+      case CHAN_CHAINADDR_HIGH:
+        assert(size == sizeof(uint32_t));
+        cr.descChainAddr =  ((uint64_t)pkt->get<uint32_t>() <<32) |
+            (cr.descChainAddr & mask(32));
+        DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
+        break;
+      case CHAN_COMMAND:
+        assert(size == sizeof(uint8_t));
+        cr.command(pkt->get<uint8_t>());
+        recvCommand();
+        break;
+      case CHAN_CMPLNADDR:
+        assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
+        if (size == sizeof(uint64_t))
+            cr.completionAddr = pkt->get<uint64_t>();
+        else
+            cr.completionAddr =  pkt->get<uint32_t>() |
+                (cr.completionAddr & ~mask(32));
+        break;
+      case CHAN_CMPLNADDR_HIGH:
+        assert(size == sizeof(uint32_t));
+        cr.completionAddr =  ((uint64_t)pkt->get<uint32_t>() <<32) |
+            (cr.completionAddr & mask(32));
+        break;
+      case CHAN_ERROR:
+        assert(size == sizeof(uint32_t));
+        cr.error(~pkt->get<uint32_t>() & cr.error());
+        break;
+      default:
+        panic("Read request to unknown channel register number: (%d)%#x\n",
+                channelId, daddr);
+    }
+}
+
+void
+CopyEngine::regStats()
+{
+    using namespace Stats;
+    bytesCopied
+        .init(regs.chanCount)
+        .name(name() + ".bytes_copied")
+        .desc("Number of bytes copied by each engine")
+        .flags(total)
+        ;
+    copiesProcessed
+        .init(regs.chanCount)
+        .name(name() + ".copies_processed")
+        .desc("Number of copies processed by each engine")
+        .flags(total)
+        ;
+}
+
+void
+CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address)
+{
+    anDq();
+    anBegin("FetchDescriptor");
+    DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n",
+           address, ce->pciToDma(address));
+    assert(address);
+    busy = true;
+
+    DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n",
+            ce->pciToDma(address), sizeof(DmaDesc), curDmaDesc);
+
+    cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(address),
+                     sizeof(DmaDesc), &fetchCompleteEvent,
+                     (uint8_t*)curDmaDesc, latBeforeBegin);
+    lastDescriptorAddr = address;
+}
+
+void
+CopyEngine::CopyEngineChannel::fetchDescComplete()
+{
+    DPRINTF(DMACopyEngine, "Read of descriptor complete\n");
+
+    if ((curDmaDesc->command & DESC_CTRL_NULL)) {
+        DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n");
+        assert(!(curDmaDesc->command & DESC_CTRL_CP_STS));
+        if (curDmaDesc->command & DESC_CTRL_CP_STS) {
+            panic("Shouldn't be able to get here\n");
+            nextState = CompletionWrite;
+            if (inDrain()) return;
+            writeCompletionStatus();
+        } else {
+            anBegin("Idle");
+            anWait();
+            busy = false;
+            nextState = Idle;
+            inDrain();
+        }
+        return;
+    }
+
+    if (curDmaDesc->command & ~DESC_CTRL_CP_STS)
+        panic("Descriptor has flag other that completion status set\n");
+
+    nextState = DMARead;
+    if (inDrain()) return;
+    readCopyBytes();
+}
+
+void
+CopyEngine::CopyEngineChannel::readCopyBytes()
+{
+    anBegin("ReadCopyBytes");
+    DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n",
+           curDmaDesc->len, curDmaDesc->dest,
+           ce->pciToDma(curDmaDesc->src));
+    cePort.dmaAction(MemCmd::ReadReq, ce->pciToDma(curDmaDesc->src),
+                     curDmaDesc->len, &readCompleteEvent, copyBuffer, 0);
+}
+
+void
+CopyEngine::CopyEngineChannel::readCopyBytesComplete()
+{
+    DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n");
+
+    nextState = DMAWrite;
+    if (inDrain()) return;
+    writeCopyBytes();
+}
+
+void
+CopyEngine::CopyEngineChannel::writeCopyBytes()
+{
+    anBegin("WriteCopyBytes");
+    DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n",
+           curDmaDesc->len, curDmaDesc->dest,
+           ce->pciToDma(curDmaDesc->dest));
+
+    cePort.dmaAction(MemCmd::WriteReq, ce->pciToDma(curDmaDesc->dest),
+                     curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0);
+
+    ce->bytesCopied[channelId] += curDmaDesc->len;
+    ce->copiesProcessed[channelId]++;
+}
+
+void
+CopyEngine::CopyEngineChannel::writeCopyBytesComplete()
+{
+    DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n",
+            curDmaDesc->user1);
+
+    cr.status.compl_desc_addr(lastDescriptorAddr >> 6);
+    completionDataReg = cr.status() | 1;
+
+    anQ("DMAUsedDescQ", channelId, 1);
+    anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len);
+    if (curDmaDesc->command & DESC_CTRL_CP_STS) {
+        nextState = CompletionWrite;
+        if (inDrain()) return;
+        writeCompletionStatus();
+        return;
+    }
+
+    continueProcessing();
+}
+
+void
+CopyEngine::CopyEngineChannel::continueProcessing()
+{
+    busy = false;
+
+    if (underReset) {
+        anBegin("Reset");
+        anWait();
+        underReset = false;
+        refreshNext = false;
+        busy = false;
+        nextState = Idle;
+        return;
+    }
+
+    if (curDmaDesc->next) {
+        nextState = DescriptorFetch;
+        fetchAddress = curDmaDesc->next;
+        if (inDrain()) return;
+        fetchDescriptor(curDmaDesc->next);
+    } else if (refreshNext) {
+        nextState = AddressFetch;
+        refreshNext = false;
+        if (inDrain()) return;
+        fetchNextAddr(lastDescriptorAddr);
+    } else {
+        inDrain();
+        nextState = Idle;
+        anWait();
+        anBegin("Idle");
+    }
+}
+
+void
+CopyEngine::CopyEngineChannel::writeCompletionStatus()
+{
+    anBegin("WriteCompletionStatus");
+    DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n",
+            completionDataReg, cr.completionAddr,
+            ce->pciToDma(cr.completionAddr));
+
+    cePort.dmaAction(MemCmd::WriteReq,
+                     ce->pciToDma(cr.completionAddr),
+                     sizeof(completionDataReg), &statusCompleteEvent,
+                     (uint8_t*)&completionDataReg, latAfterCompletion);
+}
+
+void
+CopyEngine::CopyEngineChannel::writeStatusComplete()
+{
+    DPRINTF(DMACopyEngine, "Writing completion status complete\n");
+    continueProcessing();
+}
+
+void
+CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address)
+{
+    anBegin("FetchNextAddr");
+    DPRINTF(DMACopyEngine, "Fetching next address...\n");
+    busy = true;
+    cePort.dmaAction(MemCmd::ReadReq,
+                     ce->pciToDma(address + offsetof(DmaDesc, next)),
+                     sizeof(Addr), &addrCompleteEvent,
+                     (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0);
+}
+
+void
+CopyEngine::CopyEngineChannel::fetchAddrComplete()
+{
+    DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n",
+            curDmaDesc->next);
+    if (!curDmaDesc->next) {
+        DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n");
+        busy = false;
+        nextState = Idle;
+        anWait();
+        anBegin("Idle");
+        inDrain();
+        return;
+    }
+    nextState = DescriptorFetch;
+    fetchAddress = curDmaDesc->next;
+    if (inDrain()) return;
+    fetchDescriptor(curDmaDesc->next);
+}
+
+bool
+CopyEngine::CopyEngineChannel::inDrain()
+{
+    if (drainState() == DrainState::Draining) {
+        DPRINTF(Drain, "CopyEngine done draining, processing drain event\n");
+        signalDrainDone();
+    }
+
+    return ce->drainState() != DrainState::Running;
+}
+
+DrainState
+CopyEngine::CopyEngineChannel::drain()
+{
+    if (nextState == Idle || ce->drainState() != DrainState::Running) {
+        return DrainState::Drained;
+    } else {
+        DPRINTF(Drain, "CopyEngineChannel not drained\n");
+        return DrainState::Draining;
+    }
+}
+
+void
+CopyEngine::serialize(CheckpointOut &cp) const
+{
+    PciDevice::serialize(cp);
+    regs.serialize(cp);
+    for (int x =0; x < chan.size(); x++)
+        chan[x]->serializeSection(cp, csprintf("channel%d", x));
+}
+
+void
+CopyEngine::unserialize(CheckpointIn &cp)
+{
+    PciDevice::unserialize(cp);
+    regs.unserialize(cp);
+    for (int x = 0; x < chan.size(); x++)
+        chan[x]->unserializeSection(cp, csprintf("channel%d", x));
+}
+
+void
+CopyEngine::CopyEngineChannel::serialize(CheckpointOut &cp) const
+{
+    SERIALIZE_SCALAR(channelId);
+    SERIALIZE_SCALAR(busy);
+    SERIALIZE_SCALAR(underReset);
+    SERIALIZE_SCALAR(refreshNext);
+    SERIALIZE_SCALAR(lastDescriptorAddr);
+    SERIALIZE_SCALAR(completionDataReg);
+    SERIALIZE_SCALAR(fetchAddress);
+    int nextState = this->nextState;
+    SERIALIZE_SCALAR(nextState);
+    arrayParamOut(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
+    SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
+    cr.serialize(cp);
+
+}
+void
+CopyEngine::CopyEngineChannel::unserialize(CheckpointIn &cp)
+{
+    UNSERIALIZE_SCALAR(channelId);
+    UNSERIALIZE_SCALAR(busy);
+    UNSERIALIZE_SCALAR(underReset);
+    UNSERIALIZE_SCALAR(refreshNext);
+    UNSERIALIZE_SCALAR(lastDescriptorAddr);
+    UNSERIALIZE_SCALAR(completionDataReg);
+    UNSERIALIZE_SCALAR(fetchAddress);
+    int nextState;
+    UNSERIALIZE_SCALAR(nextState);
+    this->nextState = (ChannelState)nextState;
+    arrayParamIn(cp, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
+    UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
+    cr.unserialize(cp);
+
+}
+
+void
+CopyEngine::CopyEngineChannel::restartStateMachine()
+{
+    switch(nextState) {
+      case AddressFetch:
+        fetchNextAddr(lastDescriptorAddr);
+        break;
+      case DescriptorFetch:
+        fetchDescriptor(fetchAddress);
+        break;
+      case DMARead:
+        readCopyBytes();
+        break;
+      case DMAWrite:
+        writeCopyBytes();
+        break;
+      case CompletionWrite:
+        writeCompletionStatus();
+        break;
+      case Idle:
+        break;
+      default:
+        panic("Unknown state for CopyEngineChannel\n");
+    }
+}
+
+void
+CopyEngine::CopyEngineChannel::drainResume()
+{
+    DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
+    restartStateMachine();
+}
+
+CopyEngine *
+CopyEngineParams::create()
+{
+    return new CopyEngine(this);
+}
diff --git a/src/dev/pci/copy_engine.hh b/src/dev/pci/copy_engine.hh
new file mode 100644 (file)
index 0000000..f548c47
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/* @file
+ * Device model for Intel's I/O Acceleration Technology (I/OAT).
+ * A DMA asyncronous copy engine
+ */
+
+#ifndef __DEV_PCI_COPY_ENGINE_HH__
+#define __DEV_PCI_COPY_ENGINE_HH__
+
+#include <vector>
+
+#include "base/cp_annotate.hh"
+#include "base/statistics.hh"
+#include "dev/pci/copy_engine_defs.hh"
+#include "dev/pci/device.hh"
+#include "params/CopyEngine.hh"
+#include "sim/drain.hh"
+#include "sim/eventq.hh"
+
+class CopyEngine : public PciDevice
+{
+    class CopyEngineChannel : public Drainable, public Serializable
+    {
+      private:
+        DmaPort cePort;
+        CopyEngine *ce;
+        CopyEngineReg::ChanRegs  cr;
+        int channelId;
+        CopyEngineReg::DmaDesc *curDmaDesc;
+        uint8_t *copyBuffer;
+
+        bool busy;
+        bool underReset;
+        bool refreshNext;
+        Addr lastDescriptorAddr;
+        Addr fetchAddress;
+
+        Tick latBeforeBegin;
+        Tick latAfterCompletion;
+
+        uint64_t completionDataReg;
+
+        enum ChannelState {
+            Idle,
+            AddressFetch,
+            DescriptorFetch,
+            DMARead,
+            DMAWrite,
+            CompletionWrite
+        };
+
+        ChannelState nextState;
+
+      public:
+        CopyEngineChannel(CopyEngine *_ce, int cid);
+        virtual ~CopyEngineChannel();
+        BaseMasterPort &getMasterPort();
+
+        std::string name() { assert(ce); return ce->name() + csprintf("-chan%d", channelId); }
+        virtual Tick read(PacketPtr pkt)
+                        { panic("CopyEngineChannel has no I/O access\n");}
+        virtual Tick write(PacketPtr pkt)
+                        { panic("CopyEngineChannel has no I/O access\n"); }
+
+        void channelRead(PacketPtr pkt, Addr daddr, int size);
+        void channelWrite(PacketPtr pkt, Addr daddr, int size);
+
+        DrainState drain() override;
+        void drainResume() override;
+
+        void serialize(CheckpointOut &cp) const override;
+        void unserialize(CheckpointIn &cp) override;
+
+      private:
+        void fetchDescriptor(Addr address);
+        void fetchDescComplete();
+        EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchDescComplete>
+            fetchCompleteEvent;
+
+        void fetchNextAddr(Addr address);
+        void fetchAddrComplete();
+        EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchAddrComplete>
+            addrCompleteEvent;
+
+        void readCopyBytes();
+        void readCopyBytesComplete();
+        EventWrapper<CopyEngineChannel, &CopyEngineChannel::readCopyBytesComplete>
+            readCompleteEvent;
+
+        void writeCopyBytes();
+        void writeCopyBytesComplete();
+        EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeCopyBytesComplete>
+            writeCompleteEvent;
+
+        void writeCompletionStatus();
+        void writeStatusComplete();
+        EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeStatusComplete>
+            statusCompleteEvent;
+
+
+        void continueProcessing();
+        void recvCommand();
+        bool inDrain();
+        void restartStateMachine();
+        inline void anBegin(const char *s)
+        {
+            CPA::cpa()->hwBegin(CPA::FL_NONE, ce->sys,
+                         channelId, "CopyEngine", s);
+        }
+
+        inline void anWait()
+        {
+            CPA::cpa()->hwWe(CPA::FL_NONE, ce->sys,
+                     channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
+        }
+
+        inline void anDq()
+        {
+            CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys,
+                      channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
+        }
+
+        inline void anPq()
+        {
+            CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys,
+                      channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
+        }
+
+        inline void anQ(const char * s, uint64_t id, int size = 1)
+        {
+            CPA::cpa()->hwQ(CPA::FL_NONE, ce->sys, channelId,
+                    "CopyEngine", s, id, NULL, size);
+        }
+
+    };
+
+  private:
+
+    Stats::Vector bytesCopied;
+    Stats::Vector copiesProcessed;
+
+    // device registers
+    CopyEngineReg::Regs regs;
+
+    // Array of channels each one with regs/dma port/etc
+    std::vector<CopyEngineChannel*> chan;
+
+  public:
+    typedef CopyEngineParams Params;
+    const Params *
+    params() const
+    {
+        return dynamic_cast<const Params *>(_params);
+    }
+    CopyEngine(const Params *params);
+    ~CopyEngine();
+
+    void regStats() override;
+
+    BaseMasterPort &getMasterPort(const std::string &if_name,
+                                  PortID idx = InvalidPortID) override;
+
+    Tick read(PacketPtr pkt) override;
+    Tick write(PacketPtr pkt) override;
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+};
+
+#endif //__DEV_PCI_COPY_ENGINE_HH__
+
diff --git a/src/dev/pci/copy_engine_defs.hh b/src/dev/pci/copy_engine_defs.hh
new file mode 100644 (file)
index 0000000..9a88802
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/* @file
+ * Register and structure descriptions for Intel's I/O AT DMA Engine
+ */
+#include "base/bitfield.hh"
+#include "sim/serialize.hh"
+
+namespace CopyEngineReg {
+
+
+// General Channel independant registers, 128 bytes starting at 0x00
+const uint32_t GEN_CHANCOUNT    = 0x00;
+const uint32_t GEN_XFERCAP      = 0x01;
+const uint32_t GEN_INTRCTRL     = 0x03;
+const uint32_t GEN_ATTNSTATUS   = 0x04;
+
+
+// Channel specific registers, each block is 128 bytes, starting at 0x80
+const uint32_t CHAN_CONTROL         = 0x00;
+const uint32_t CHAN_STATUS          = 0x04;
+const uint32_t CHAN_CHAINADDR       = 0x0C;
+const uint32_t CHAN_CHAINADDR_LOW   = 0x0C;
+const uint32_t CHAN_CHAINADDR_HIGH  = 0x10;
+const uint32_t CHAN_COMMAND         = 0x14;
+const uint32_t CHAN_CMPLNADDR       = 0x18;
+const uint32_t CHAN_CMPLNADDR_LOW   = 0x18;
+const uint32_t CHAN_CMPLNADDR_HIGH  = 0x1C;
+const uint32_t CHAN_ERROR           = 0x28;
+
+
+const uint32_t DESC_CTRL_INT_GEN    = 0x00000001;
+const uint32_t DESC_CTRL_SRC_SN     = 0x00000002;
+const uint32_t DESC_CTRL_DST_SN     = 0x00000004;
+const uint32_t DESC_CTRL_CP_STS     = 0x00000008;
+const uint32_t DESC_CTRL_FRAME      = 0x00000010;
+const uint32_t DESC_CTRL_NULL       = 0x00000020;
+
+struct DmaDesc {
+    uint32_t len;
+    uint32_t command;
+    Addr src;
+    Addr dest;
+    Addr next;
+    uint64_t reserved1;
+    uint64_t reserved2;
+    uint64_t user1;
+    uint64_t user2;
+};
+
+#define ADD_FIELD8(NAME, OFFSET, BITS) \
+    inline uint8_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+    inline void NAME(uint8_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+#define ADD_FIELD16(NAME, OFFSET, BITS) \
+    inline uint16_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+    inline void NAME(uint16_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+#define ADD_FIELD32(NAME, OFFSET, BITS) \
+    inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+    inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+#define ADD_FIELD64(NAME, OFFSET, BITS) \
+    inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+    inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+template<class T>
+struct Reg {
+    T _data;
+    T operator()() { return _data; }
+    const Reg<T> &operator=(T d) { _data = d; return *this;}
+    bool operator==(T d) { return d == _data; }
+    void operator()(T d) { _data = d; }
+    Reg() { _data = 0; }
+    void serialize(CheckpointOut &cp) const
+    {
+        SERIALIZE_SCALAR(_data);
+    }
+    void unserialize(CheckpointIn &cp)
+    {
+        UNSERIALIZE_SCALAR(_data);
+    }
+};
+
+
+struct Regs : public Serializable {
+    uint8_t chanCount;
+    uint8_t xferCap;
+
+    struct INTRCTRL : public Reg<uint8_t> { // 0x03
+        using Reg<uint8_t>::operator =;
+        ADD_FIELD8(master_int_enable,0,1);
+        ADD_FIELD8(interrupt_status,1,1);
+        ADD_FIELD8(interrupt,2,1);
+    };
+    INTRCTRL intrctrl;
+
+    uint32_t attnStatus; // Read clears
+
+    void serialize(CheckpointOut &cp) const override
+    {
+        SERIALIZE_SCALAR(chanCount);
+        SERIALIZE_SCALAR(xferCap);
+        paramOut(cp, "intrctrl", intrctrl._data);
+        SERIALIZE_SCALAR(attnStatus);
+    }
+
+    void unserialize(CheckpointIn &cp) override
+    {
+        UNSERIALIZE_SCALAR(chanCount);
+        UNSERIALIZE_SCALAR(xferCap);
+        paramIn(cp, "intrctrl", intrctrl._data);
+        UNSERIALIZE_SCALAR(attnStatus);
+    }
+
+};
+
+struct ChanRegs : public Serializable {
+    struct CHANCTRL : public Reg<uint16_t> { // channelX + 0x00
+        using Reg<uint16_t>::operator =;
+        ADD_FIELD16(interrupt_disable,0,1);
+        ADD_FIELD16(error_completion_enable, 2,1);
+        ADD_FIELD16(any_error_abort_enable,3,1);
+        ADD_FIELD16(error_int_enable,4,1);
+        ADD_FIELD16(desc_addr_snoop_control,5,1);
+        ADD_FIELD16(in_use, 8,1);
+    };
+    CHANCTRL ctrl;
+
+    struct CHANSTS : public Reg<uint64_t> { // channelX + 0x04
+        ADD_FIELD64(dma_transfer_status, 0, 3);
+        ADD_FIELD64(unaffiliated_error, 3, 1);
+        ADD_FIELD64(soft_error, 4, 1);
+        ADD_FIELD64(compl_desc_addr, 6, 58);
+    };
+    CHANSTS status;
+
+    uint64_t descChainAddr;
+
+    struct CHANCMD : public Reg<uint8_t> { // channelX + 0x14
+        ADD_FIELD8(start_dma,0,1);
+        ADD_FIELD8(append_dma,1,1);
+        ADD_FIELD8(suspend_dma,2,1);
+        ADD_FIELD8(abort_dma,3,1);
+        ADD_FIELD8(resume_dma,4,1);
+        ADD_FIELD8(reset_dma,5,1);
+    };
+    CHANCMD command;
+
+    uint64_t completionAddr;
+
+    struct CHANERR : public Reg<uint32_t> { // channel X + 0x28
+        ADD_FIELD32(source_addr_error,0,1);
+        ADD_FIELD32(dest_addr_error,1,1);
+        ADD_FIELD32(ndesc_addr_error,2,1);
+        ADD_FIELD32(desc_error,3,1);
+        ADD_FIELD32(chain_addr_error,4,1);
+        ADD_FIELD32(chain_cmd_error,5,1);
+        ADD_FIELD32(chipset_parity_error,6,1);
+        ADD_FIELD32(dma_parity_error,7,1);
+        ADD_FIELD32(read_data_error,8,1);
+        ADD_FIELD32(write_data_error,9,1);
+        ADD_FIELD32(desc_control_error,10,1);
+        ADD_FIELD32(desc_len_error,11,1);
+        ADD_FIELD32(completion_addr_error,12,1);
+        ADD_FIELD32(interrupt_config_error,13,1);
+        ADD_FIELD32(soft_error,14,1);
+        ADD_FIELD32(unaffiliated_error,15,1);
+    };
+    CHANERR error;
+
+    void serialize(CheckpointOut &cp) const override
+    {
+        paramOut(cp, "ctrl", ctrl._data);
+        paramOut(cp, "status", status._data);
+        SERIALIZE_SCALAR(descChainAddr);
+        paramOut(cp, "command", command._data);
+        SERIALIZE_SCALAR(completionAddr);
+        paramOut(cp, "error", error._data);
+    }
+
+    void unserialize(CheckpointIn &cp) override
+    {
+        paramIn(cp, "ctrl", ctrl._data);
+        paramIn(cp, "status", status._data);
+        UNSERIALIZE_SCALAR(descChainAddr);
+        paramIn(cp, "command", command._data);
+        UNSERIALIZE_SCALAR(completionAddr);
+        paramIn(cp, "error", error._data);
+    }
+
+
+};
+
+} // namespace CopyEngineReg
+
+