diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/arm/table_walker.hh | 2 | ||||
-rw-r--r-- | src/dev/SConscript | 1 | ||||
-rw-r--r-- | src/dev/arm/amba_device.hh | 1 | ||||
-rw-r--r-- | src/dev/dma_device.cc | 310 | ||||
-rw-r--r-- | src/dev/dma_device.hh | 171 | ||||
-rw-r--r-- | src/dev/io_device.cc | 275 | ||||
-rw-r--r-- | src/dev/io_device.hh | 134 | ||||
-rw-r--r-- | src/dev/pcidev.hh | 2 |
8 files changed, 486 insertions, 410 deletions
diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index 36adc8a82..db6b01cd4 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -44,7 +44,7 @@ #include "arch/arm/miscregs.hh" #include "arch/arm/tlb.hh" -#include "dev/io_device.hh" +#include "dev/dma_device.hh" #include "mem/mem_object.hh" #include "mem/request.hh" #include "params/ArmTableWalker.hh" diff --git a/src/dev/SConscript b/src/dev/SConscript index c041081b5..cba821f87 100644 --- a/src/dev/SConscript +++ b/src/dev/SConscript @@ -49,6 +49,7 @@ SimObject('Uart.py') Source('baddev.cc') Source('copy_engine.cc') Source('disk_image.cc') +Source('dma_device.cc') Source('etherbus.cc') Source('etherdevice.cc') Source('etherdump.cc') diff --git a/src/dev/arm/amba_device.hh b/src/dev/arm/amba_device.hh index f3db8b0ab..4bea1e075 100644 --- a/src/dev/arm/amba_device.hh +++ b/src/dev/arm/amba_device.hh @@ -51,6 +51,7 @@ #include "base/range.hh" #include "dev/arm/gic.hh" +#include "dev/dma_device.hh" #include "dev/io_device.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" diff --git a/src/dev/dma_device.cc b/src/dev/dma_device.cc new file mode 100644 index 000000000..401f910ac --- /dev/null +++ b/src/dev/dma_device.cc @@ -0,0 +1,310 @@ +/* + * 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) 2006 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 + * Nathan Binkert + */ + +#include "base/chunk_generator.hh" +#include "debug/DMA.hh" +#include "dev/dma_device.hh" +#include "sim/system.hh" + +DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff) + : MasterPort(dev->name() + "-dma", dev), device(dev), sys(s), + masterId(s->getMasterId(dev->name())), + pendingCount(0), actionInProgress(0), drainEvent(NULL), + backoffTime(0), minBackoffDelay(min_backoff), + maxBackoffDelay(max_backoff), inRetry(false), + backoffEvent(this) +{ } + +bool +DmaPort::recvTimingResp(PacketPtr pkt) +{ + if (pkt->wasNacked()) { + DPRINTF(DMA, "Received nacked %s addr %#x\n", + pkt->cmdString(), pkt->getAddr()); + + if (backoffTime < minBackoffDelay) + backoffTime = minBackoffDelay; + else if (backoffTime < maxBackoffDelay) + backoffTime <<= 1; + + device->reschedule(backoffEvent, curTick() + backoffTime, true); + + DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime); + + pkt->reinitNacked(); + queueDma(pkt, true); + } else if (pkt->senderState) { + DmaReqState *state; + backoffTime >>= 2; + + DPRINTF(DMA, "Received response %s addr %#x size %#x\n", + pkt->cmdString(), pkt->getAddr(), pkt->req->getSize()); + state = dynamic_cast<DmaReqState*>(pkt->senderState); + pendingCount--; + + assert(pendingCount >= 0); + assert(state); + + // We shouldn't ever get a block in ownership state + assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); + + state->numBytes += pkt->req->getSize(); + assert(state->totBytes >= state->numBytes); + if (state->totBytes == state->numBytes) { + if (state->completionEvent) { + if (state->delay) + device->schedule(state->completionEvent, + curTick() + state->delay); + else + state->completionEvent->process(); + } + delete state; + } + delete pkt->req; + delete pkt; + + if (pendingCount == 0 && drainEvent) { + drainEvent->process(); + drainEvent = NULL; + } + } else { + panic("Got packet without sender state... huh?\n"); + } + + return true; +} + +DmaDevice::DmaDevice(const Params *p) + : PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay, + params()->max_backoff_delay) +{ } + +void +DmaDevice::init() +{ + if (!dmaPort.isConnected()) + panic("DMA port of %s not connected to anything!", name()); + PioDevice::init(); +} + +unsigned int +DmaDevice::drain(Event *de) +{ + unsigned int count; + count = pioPort.drain(de) + dmaPort.drain(de); + if (count) + changeState(Draining); + else + changeState(Drained); + return count; +} + +unsigned int +DmaPort::drain(Event *de) +{ + if (pendingCount == 0) + return 0; + drainEvent = de; + return 1; +} + +void +DmaPort::recvRetry() +{ + assert(transmitList.size()); + bool result = true; + do { + PacketPtr pkt = transmitList.front(); + DPRINTF(DMA, "Retry on %s addr %#x\n", + pkt->cmdString(), pkt->getAddr()); + result = sendTimingReq(pkt); + if (result) { + DPRINTF(DMA, "-- Done\n"); + transmitList.pop_front(); + inRetry = false; + } else { + inRetry = true; + DPRINTF(DMA, "-- Failed, queued\n"); + } + } while (!backoffTime && result && transmitList.size()); + + if (transmitList.size() && backoffTime && !inRetry) { + DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime); + if (!backoffEvent.scheduled()) + device->schedule(backoffEvent, backoffTime + curTick()); + } + DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", + transmitList.size(), backoffTime, inRetry, + backoffEvent.scheduled()); +} + +void +DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, + uint8_t *data, Tick delay, Request::Flags flag) +{ + assert(device->getState() == SimObject::Running); + + DmaReqState *reqState = new DmaReqState(event, size, delay); + + + DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size, + event ? event->scheduled() : -1 ); + for (ChunkGenerator gen(addr, size, peerBlockSize()); + !gen.done(); gen.next()) { + Request *req = new Request(gen.addr(), gen.size(), flag, masterId); + PacketPtr pkt = new Packet(req, cmd); + + // Increment the data pointer on a write + if (data) + pkt->dataStatic(data + gen.complete()); + + pkt->senderState = reqState; + + assert(pendingCount >= 0); + pendingCount++; + DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), + gen.size()); + queueDma(pkt); + } + +} + +void +DmaPort::queueDma(PacketPtr pkt, bool front) +{ + + if (front) + transmitList.push_front(pkt); + else + transmitList.push_back(pkt); + sendDma(); +} + +void +DmaPort::sendDma() +{ + // some kind of selction between access methods + // more work is going to have to be done to make + // switching actually work + assert(transmitList.size()); + PacketPtr pkt = transmitList.front(); + + Enums::MemoryMode state = sys->getMemoryMode(); + if (state == Enums::timing) { + if (backoffEvent.scheduled() || inRetry) { + DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n"); + return; + } + + DPRINTF(DMA, "Attempting to send %s addr %#x\n", + pkt->cmdString(), pkt->getAddr()); + + bool result; + do { + result = sendTimingReq(pkt); + if (result) { + transmitList.pop_front(); + DPRINTF(DMA, "-- Done\n"); + } else { + inRetry = true; + DPRINTF(DMA, "-- Failed: queued\n"); + } + } while (result && !backoffTime && transmitList.size()); + + if (transmitList.size() && backoffTime && !inRetry && + !backoffEvent.scheduled()) { + DPRINTF(DMA, "-- Scheduling backoff timer for %d\n", + backoffTime+curTick()); + device->schedule(backoffEvent, backoffTime + curTick()); + } + } else if (state == Enums::atomic) { + transmitList.pop_front(); + + Tick lat; + DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n", + pkt->req->getPaddr(), pkt->req->getSize()); + lat = sendAtomic(pkt); + assert(pkt->senderState); + DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); + assert(state); + state->numBytes += pkt->req->getSize(); + + DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n", + pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes, + state->totBytes, + state->completionEvent ? state->completionEvent->scheduled() : 0 ); + + if (state->totBytes == state->numBytes) { + if (state->completionEvent) { + assert(!state->completionEvent->scheduled()); + device->schedule(state->completionEvent, + curTick() + lat + state->delay); + } + delete state; + delete pkt->req; + } + pendingCount--; + assert(pendingCount >= 0); + delete pkt; + + if (pendingCount == 0 && drainEvent) { + drainEvent->process(); + drainEvent = NULL; + } + + } else + panic("Unknown memory command state."); +} + +DmaDevice::~DmaDevice() +{ +} + +MasterPort & +DmaDevice::getMasterPort(const std::string &if_name, int idx) +{ + if (if_name == "dma") { + return dmaPort; + } + return PioDevice::getMasterPort(if_name, idx); +} diff --git a/src/dev/dma_device.hh b/src/dev/dma_device.hh new file mode 100644 index 000000000..8fc4e664c --- /dev/null +++ b/src/dev/dma_device.hh @@ -0,0 +1,171 @@ +/* + * 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) 2004-2005 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 + * Nathan Binkert + */ + +#ifndef __DEV_DMA_DEVICE_HH__ +#define __DEV_DMA_DEVICE_HH__ + +#include "dev/io_device.hh" +#include "params/DmaDevice.hh" + +class DmaPort : public MasterPort +{ + protected: + struct DmaReqState : public Packet::SenderState, public FastAlloc + { + /** Event to call on the device when this transaction (all packets) + * complete. */ + Event *completionEvent; + + /** Total number of bytes that this transaction involves. */ + Addr totBytes; + + /** Number of bytes that have been acked for this transaction. */ + Addr numBytes; + + /** Amount to delay completion of dma by */ + Tick delay; + + DmaReqState(Event *ce, Addr tb, Tick _delay) + : completionEvent(ce), totBytes(tb), numBytes(0), delay(_delay) + {} + }; + + MemObject *device; + std::list<PacketPtr> transmitList; + + /** The system that device/port are in. This is used to select which mode + * we are currently operating in. */ + System *sys; + + /** Id for all requests */ + MasterID masterId; + + /** Number of outstanding packets the dma port has. */ + int pendingCount; + + /** If a dmaAction is in progress. */ + int actionInProgress; + + /** If we need to drain, keep the drain event around until we're done + * here.*/ + Event *drainEvent; + + /** time to wait between sending another packet, increases as NACKs are + * recived, decreases as responses are recived. */ + Tick backoffTime; + + /** Minimum time that device should back off for after failed sendTiming */ + Tick minBackoffDelay; + + /** Maximum time that device should back off for after failed sendTiming */ + Tick maxBackoffDelay; + + /** If the port is currently waiting for a retry before it can send whatever + * it is that it's sending. */ + bool inRetry; + + virtual bool recvTimingResp(PacketPtr pkt); + + virtual void recvRetry() ; + + void queueDma(PacketPtr pkt, bool front = false); + void sendDma(); + + /** event to give us a kick every time we backoff time is reached. */ + EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent; + + public: + DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff); + + void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, + uint8_t *data, Tick delay, Request::Flags flag = 0); + + bool dmaPending() { return pendingCount > 0; } + + unsigned cacheBlockSize() const { return peerBlockSize(); } + unsigned int drain(Event *de); +}; + +class DmaDevice : public PioDevice +{ + protected: + DmaPort dmaPort; + + public: + typedef DmaDeviceParams Params; + DmaDevice(const Params *p); + virtual ~DmaDevice(); + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, + Tick delay = 0) + { + dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, delay); + } + + void dmaRead(Addr addr, int size, Event *event, uint8_t *data, + Tick delay = 0) + { + dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, delay); + } + + bool dmaPending() { return dmaPort.dmaPending(); } + + virtual void init(); + + virtual unsigned int drain(Event *de); + + unsigned cacheBlockSize() const { return dmaPort.cacheBlockSize(); } + + virtual MasterPort &getMasterPort(const std::string &if_name, + int idx = -1); + + friend class DmaPort; +}; + +#endif // __DEV_DMA_DEVICE_HH__ diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc index 83d3af095..100c04828 100644 --- a/src/dev/io_device.cc +++ b/src/dev/io_device.cc @@ -41,19 +41,16 @@ * Nathan Binkert */ -#include "base/chunk_generator.hh" #include "base/trace.hh" #include "debug/BusAddrRanges.hh" -#include "debug/DMA.hh" #include "dev/io_device.hh" #include "sim/system.hh" PioPort::PioPort(PioDevice *dev) - : SimpleTimingPort(dev->name() + "-pioport", dev), device(dev) + : SimpleTimingPort(dev->name() + "-pio", dev), device(dev) { } - Tick PioPort::recvAtomic(PacketPtr pkt) { @@ -66,7 +63,6 @@ PioPort::getAddrRanges() return device->getAddrRanges(); } - PioDevice::PioDevice(const Params *p) : MemObject(p), sys(p->system), pioPort(this) {} @@ -118,272 +114,3 @@ BasicPioDevice::getAddrRanges() ranges.push_back(RangeSize(pioAddr, pioSize)); return ranges; } - - -DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff) - : MasterPort(dev->name() + "-dma", dev), device(dev), sys(s), - masterId(s->getMasterId(dev->name())), - pendingCount(0), actionInProgress(0), drainEvent(NULL), - backoffTime(0), minBackoffDelay(min_backoff), - maxBackoffDelay(max_backoff), inRetry(false), - backoffEvent(this) -{ } - -bool -DmaPort::recvTimingResp(PacketPtr pkt) -{ - if (pkt->wasNacked()) { - DPRINTF(DMA, "Received nacked %s addr %#x\n", - pkt->cmdString(), pkt->getAddr()); - - if (backoffTime < minBackoffDelay) - backoffTime = minBackoffDelay; - else if (backoffTime < maxBackoffDelay) - backoffTime <<= 1; - - device->reschedule(backoffEvent, curTick() + backoffTime, true); - - DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime); - - pkt->reinitNacked(); - queueDma(pkt, true); - } else if (pkt->senderState) { - DmaReqState *state; - backoffTime >>= 2; - - DPRINTF(DMA, "Received response %s addr %#x size %#x\n", - pkt->cmdString(), pkt->getAddr(), pkt->req->getSize()); - state = dynamic_cast<DmaReqState*>(pkt->senderState); - pendingCount--; - - assert(pendingCount >= 0); - assert(state); - - // We shouldn't ever get a block in ownership state - assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); - - state->numBytes += pkt->req->getSize(); - assert(state->totBytes >= state->numBytes); - if (state->totBytes == state->numBytes) { - if (state->completionEvent) { - if (state->delay) - device->schedule(state->completionEvent, - curTick() + state->delay); - else - state->completionEvent->process(); - } - delete state; - } - delete pkt->req; - delete pkt; - - if (pendingCount == 0 && drainEvent) { - drainEvent->process(); - drainEvent = NULL; - } - } else { - panic("Got packet without sender state... huh?\n"); - } - - return true; -} - -DmaDevice::DmaDevice(const Params *p) - : PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay, - params()->max_backoff_delay) -{ } - -void -DmaDevice::init() -{ - if (!dmaPort.isConnected()) - panic("DMA port of %s not connected to anything!", name()); - PioDevice::init(); -} - -unsigned int -DmaDevice::drain(Event *de) -{ - unsigned int count; - count = pioPort.drain(de) + dmaPort.drain(de); - if (count) - changeState(Draining); - else - changeState(Drained); - return count; -} - -unsigned int -DmaPort::drain(Event *de) -{ - if (pendingCount == 0) - return 0; - drainEvent = de; - return 1; -} - - -void -DmaPort::recvRetry() -{ - assert(transmitList.size()); - bool result = true; - do { - PacketPtr pkt = transmitList.front(); - DPRINTF(DMA, "Retry on %s addr %#x\n", - pkt->cmdString(), pkt->getAddr()); - result = sendTimingReq(pkt); - if (result) { - DPRINTF(DMA, "-- Done\n"); - transmitList.pop_front(); - inRetry = false; - } else { - inRetry = true; - DPRINTF(DMA, "-- Failed, queued\n"); - } - } while (!backoffTime && result && transmitList.size()); - - if (transmitList.size() && backoffTime && !inRetry) { - DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime); - if (!backoffEvent.scheduled()) - device->schedule(backoffEvent, backoffTime + curTick()); - } - DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", - transmitList.size(), backoffTime, inRetry, - backoffEvent.scheduled()); -} - - -void -DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, - uint8_t *data, Tick delay, Request::Flags flag) -{ - assert(device->getState() == SimObject::Running); - - DmaReqState *reqState = new DmaReqState(event, this, size, delay); - - - DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size, - event ? event->scheduled() : -1 ); - for (ChunkGenerator gen(addr, size, peerBlockSize()); - !gen.done(); gen.next()) { - Request *req = new Request(gen.addr(), gen.size(), flag, masterId); - PacketPtr pkt = new Packet(req, cmd); - - // Increment the data pointer on a write - if (data) - pkt->dataStatic(data + gen.complete()); - - pkt->senderState = reqState; - - assert(pendingCount >= 0); - pendingCount++; - DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), - gen.size()); - queueDma(pkt); - } - -} - -void -DmaPort::queueDma(PacketPtr pkt, bool front) -{ - - if (front) - transmitList.push_front(pkt); - else - transmitList.push_back(pkt); - sendDma(); -} - - -void -DmaPort::sendDma() -{ - // some kind of selction between access methods - // more work is going to have to be done to make - // switching actually work - assert(transmitList.size()); - PacketPtr pkt = transmitList.front(); - - Enums::MemoryMode state = sys->getMemoryMode(); - if (state == Enums::timing) { - if (backoffEvent.scheduled() || inRetry) { - DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n"); - return; - } - - DPRINTF(DMA, "Attempting to send %s addr %#x\n", - pkt->cmdString(), pkt->getAddr()); - - bool result; - do { - result = sendTimingReq(pkt); - if (result) { - transmitList.pop_front(); - DPRINTF(DMA, "-- Done\n"); - } else { - inRetry = true; - DPRINTF(DMA, "-- Failed: queued\n"); - } - } while (result && !backoffTime && transmitList.size()); - - if (transmitList.size() && backoffTime && !inRetry && - !backoffEvent.scheduled()) { - DPRINTF(DMA, "-- Scheduling backoff timer for %d\n", - backoffTime+curTick()); - device->schedule(backoffEvent, backoffTime + curTick()); - } - } else if (state == Enums::atomic) { - transmitList.pop_front(); - - Tick lat; - DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n", - pkt->req->getPaddr(), pkt->req->getSize()); - lat = sendAtomic(pkt); - assert(pkt->senderState); - DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); - assert(state); - state->numBytes += pkt->req->getSize(); - - DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n", - pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes, - state->totBytes, - state->completionEvent ? state->completionEvent->scheduled() : 0 ); - - if (state->totBytes == state->numBytes) { - if (state->completionEvent) { - assert(!state->completionEvent->scheduled()); - device->schedule(state->completionEvent, - curTick() + lat + state->delay); - } - delete state; - delete pkt->req; - } - pendingCount--; - assert(pendingCount >= 0); - delete pkt; - - if (pendingCount == 0 && drainEvent) { - drainEvent->process(); - drainEvent = NULL; - } - - } else - panic("Unknown memory command state."); -} - -DmaDevice::~DmaDevice() -{ -} - - -MasterPort & -DmaDevice::getMasterPort(const std::string &if_name, int idx) -{ - if (if_name == "dma") { - return dmaPort; - } - return PioDevice::getMasterPort(if_name, idx); -} - diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh index 0e6556a50..3f2802332 100644 --- a/src/dev/io_device.hh +++ b/src/dev/io_device.hh @@ -44,18 +44,12 @@ #ifndef __DEV_IO_DEVICE_HH__ #define __DEV_IO_DEVICE_HH__ -#include "base/fast_alloc.hh" #include "mem/mem_object.hh" -#include "mem/packet.hh" #include "mem/tport.hh" #include "params/BasicPioDevice.hh" -#include "params/DmaDevice.hh" #include "params/PioDevice.hh" -#include "sim/sim_object.hh" -class Event; class PioDevice; -class DmaDevice; class System; /** @@ -80,91 +74,6 @@ class PioPort : public SimpleTimingPort PioPort(PioDevice *dev); }; - -class DmaPort : public MasterPort -{ - protected: - struct DmaReqState : public Packet::SenderState, public FastAlloc - { - /** Event to call on the device when this transaction (all packets) - * complete. */ - Event *completionEvent; - - /** Where we came from for some sanity checking. */ - Port *outPort; - - /** Total number of bytes that this transaction involves. */ - Addr totBytes; - - /** Number of bytes that have been acked for this transaction. */ - Addr numBytes; - - /** Amount to delay completion of dma by */ - Tick delay; - - - DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay) - : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0), - delay(_delay) - {} - }; - - MemObject *device; - std::list<PacketPtr> transmitList; - - /** The system that device/port are in. This is used to select which mode - * we are currently operating in. */ - System *sys; - - /** Id for all requests */ - MasterID masterId; - - /** Number of outstanding packets the dma port has. */ - int pendingCount; - - /** If a dmaAction is in progress. */ - int actionInProgress; - - /** If we need to drain, keep the drain event around until we're done - * here.*/ - Event *drainEvent; - - /** time to wait between sending another packet, increases as NACKs are - * recived, decreases as responses are recived. */ - Tick backoffTime; - - /** Minimum time that device should back off for after failed sendTiming */ - Tick minBackoffDelay; - - /** Maximum time that device should back off for after failed sendTiming */ - Tick maxBackoffDelay; - - /** If the port is currently waiting for a retry before it can send whatever - * it is that it's sending. */ - bool inRetry; - - virtual bool recvTimingResp(PacketPtr pkt); - - virtual void recvRetry() ; - - void queueDma(PacketPtr pkt, bool front = false); - void sendDma(); - - /** event to give us a kick every time we backoff time is reached. */ - EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent; - - public: - DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff); - - void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, - uint8_t *data, Tick delay, Request::Flags flag = 0); - - bool dmaPending() { return pendingCount > 0; } - - unsigned cacheBlockSize() const { return peerBlockSize(); } - unsigned int drain(Event *de); -}; - /** * This device is the base class which all devices senstive to an address range * inherit from. There are three pure virtual functions which all devices must @@ -255,47 +164,4 @@ class BasicPioDevice : public PioDevice }; -class DmaDevice : public PioDevice -{ - protected: - DmaPort dmaPort; - - public: - typedef DmaDeviceParams Params; - DmaDevice(const Params *p); - virtual ~DmaDevice(); - - const Params * - params() const - { - return dynamic_cast<const Params *>(_params); - } - - void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, - Tick delay = 0) - { - dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, delay); - } - - void dmaRead(Addr addr, int size, Event *event, uint8_t *data, - Tick delay = 0) - { - dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, delay); - } - - bool dmaPending() { return dmaPort.dmaPending(); } - - virtual void init(); - - virtual unsigned int drain(Event *de); - - unsigned cacheBlockSize() const { return dmaPort.cacheBlockSize(); } - - virtual MasterPort &getMasterPort(const std::string &if_name, - int idx = -1); - - friend class DmaPort; -}; - - #endif // __DEV_IO_DEVICE_HH__ diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh index 435188342..0cda0b8ea 100644 --- a/src/dev/pcidev.hh +++ b/src/dev/pcidev.hh @@ -39,7 +39,7 @@ #include <cstring> -#include "dev/io_device.hh" +#include "dev/dma_device.hh" #include "dev/pcireg.h" #include "dev/platform.hh" #include "params/PciDevice.hh" |