diff -r 164b045bd6fb -r beb437b45bd0 src/dev/Device.py --- a/src/dev/Device.py Sat Jul 21 13:16:23 2012 +0100 +++ b/src/dev/Device.py Mon Jul 23 09:31:55 2012 +0100 @@ -47,11 +47,9 @@ abstract = True dma = MasterPort("DMA port") min_backoff_delay = Param.Latency('4ns', - "min time between a nack packet being received and the next request made by the device") + "min time between a failing to send a request and trying again") max_backoff_delay = Param.Latency('10us', - "max time between a nack packet being received and the next request made by the device") - - + "max time between failing to send a request and trying again") class IsaFake(BasicPioDevice): type = 'IsaFake' diff -r 164b045bd6fb -r beb437b45bd0 src/dev/dma_device.hh --- a/src/dev/dma_device.hh Sat Jul 21 13:16:23 2012 +0100 +++ b/src/dev/dma_device.hh Mon Jul 23 09:31:55 2012 +0100 @@ -44,6 +44,8 @@ #ifndef __DEV_DMA_DEVICE_HH__ #define __DEV_DMA_DEVICE_HH__ +#include + #include "dev/io_device.hh" #include "params/DmaDevice.hh" @@ -71,7 +73,7 @@ }; MemObject *device; - std::list transmitList; + std::deque transmitList; /** The system that device/port are in. This is used to select which mode * we are currently operating in. */ @@ -81,7 +83,7 @@ MasterID masterId; /** Number of outstanding packets the dma port has. */ - int pendingCount; + uint pendingCount; /** If a dmaAction is in progress. */ int actionInProgress; @@ -90,8 +92,10 @@ * here.*/ Event *drainEvent; - /** time to wait between sending another packet, increases as NACKs are - * recived, decreases as responses are recived. */ + /** + * Time to wait before sending another request packet, increases when + * failing to send a request and decreses when succeeding. + */ Tick backoffTime; /** Minimum time that device should back off for after failed sendTiming */ @@ -104,15 +108,27 @@ * it is that it's sending. */ bool inRetry; - virtual bool recvTimingResp(PacketPtr pkt); + /** + * Handler a response packet by updating the corresponding DMA + * request state to reflect the bytes received, and also update + * the pending request counter. If the DMA request that this + * packet is part of is complete, then signal the completion event + * if present, potentially with a delay added to it. + * + * @param pkt Response packet to handler + * @param delay Additional delay for scheduling the completion event + */ + void handleResp(PacketPtr pkt, Tick delay = 0); - virtual void recvRetry() ; + bool recvTimingResp(PacketPtr pkt); - void queueDma(PacketPtr pkt, bool front = false); + void recvRetry(); + + void queueDma(PacketPtr pkt); void sendDma(); /** event to give us a kick every time we backoff time is reached. */ - EventWrapper backoffEvent; + EventWrapper sendEvent; public: DmaHandler(MemObject *dev, System *s, Tick min_backoff, @@ -121,7 +137,7 @@ 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; } + bool dmaPending() const { return pendingCount > 0; } unsigned int drain(Event *de); }; @@ -142,13 +158,7 @@ public: typedef DmaDeviceParams Params; DmaDevice(const Params *p); - virtual ~DmaDevice(); - - const Params * - params() const - { - return dynamic_cast(_params); - } + virtual ~DmaDevice() { } void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0) @@ -164,7 +174,7 @@ delay); } - bool dmaPending() { return dmaPort->dmaPending(); } + bool dmaPending() const { return dmaPort->dmaPending(); } virtual void init(); diff -r 164b045bd6fb -r beb437b45bd0 src/dev/dma_device.cc --- a/src/dev/dma_device.cc Sat Jul 21 13:16:23 2012 +0100 +++ b/src/dev/dma_device.cc Mon Jul 23 09:31:55 2012 +0100 @@ -39,6 +39,7 @@ * * Authors: Ali Saidi * Nathan Binkert + * Andreas Hansson */ #include "base/chunk_generator.hh" @@ -47,63 +48,83 @@ #include "sim/system.hh" DmaHandler::DmaHandler(MemObject *dev, System *s, Tick min_backoff, - Tick max_backoff) + Tick max_backoff) : 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) + sendEvent(this) { } +void +DmaHandler::handleResp(PacketPtr pkt, Tick delay) +{ + // should always see a response with a sender state + assert(pkt->isResponse()); + if (!pkt->senderState) + panic("DMA %s got packet without sender state\n", name()); + + // get the DMA sender state + DmaReqState *state = dynamic_cast(pkt->senderState); + assert(state); + + DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d," \ + " tot: %d sched %d\n", + pkt->cmdString(), pkt->getAddr(), pkt->req->getSize(), + state->numBytes, state->totBytes, + state->completionEvent ? + state->completionEvent->scheduled() : 0); + + assert(pendingCount != 0); + pendingCount--; + + // update the number of bytes received based on the request rather + // than the packet + state->numBytes += pkt->req->getSize(); + assert(state->totBytes >= state->numBytes); + + // if we have reached the total number of bytes for this DMA + // request, then signal the completion and delete the sate + if (state->totBytes == state->numBytes) { + if (state->completionEvent) { + delay += state->delay; + if (delay) + device->schedule(state->completionEvent, curTick() + delay); + else + state->completionEvent->process(); + } + delete state; + } + + // delete the request that we created and also the packet + delete pkt->req; + delete pkt; + + // we might be drained at this point, if so signal the drain event + if (pendingCount == 0 && drainEvent) { + drainEvent->process(); + drainEvent = NULL; + } +} + bool DmaHandler::recvTimingResp(PacketPtr pkt) { - if (pkt->senderState) { - DmaReqState *state; - backoffTime >>= 2; + // We shouldn't ever get a block in ownership state + assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); - DPRINTF(DMA, "Received response %s addr %#x size %#x\n", - pkt->cmdString(), pkt->getAddr(), pkt->req->getSize()); - state = dynamic_cast(pkt->senderState); - pendingCount--; + backoffTime >>= 2; - 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"); - } + handleResp(pkt); return true; } DmaDevice::DmaDevice(const Params *p) - : PioDevice(p), dmaHandler(this, sys, params()->min_backoff_delay, - params()->max_backoff_delay), - dmaPort(this->name() + ".dma", this, dmaHandler) + : PioDevice(p), dmaHandler(this, sys, p->min_backoff_delay, + p->max_backoff_delay), + dmaPort(name() + ".dma", this, dmaHandler) { } void @@ -117,8 +138,7 @@ unsigned int DmaDevice::drain(Event *de) { - unsigned int count; - count = pioPort->drain(de) + dmaPort->drain(de); + unsigned int count = pioPort->drain(de) + dmaPort->drain(de); if (count) changeState(Draining); else @@ -166,54 +186,56 @@ if (transmitList.size() && backoffTime && !inRetry) { DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime); - if (!backoffEvent.scheduled()) - device->schedule(backoffEvent, backoffTime + curTick()); + if (!sendEvent.scheduled()) + device->schedule(sendEvent, backoffTime + curTick()); } DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", transmitList.size(), backoffTime, inRetry, - backoffEvent.scheduled()); + sendEvent.scheduled()); } void DmaHandler::dmaAction(Packet::Command cmd, Addr addr, int size, - Event *event, uint8_t *data, Tick delay, - Request::Flags flag) + Event *event, uint8_t *data, Tick delay, + Request::Flags flag) { assert(device->getState() == SimObject::Running); + // one DMA request sender state for every action, that is then + // split into many requests and packets based on the block size, + // i.e. cache line size 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); - 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); + 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()); + // Increment the data pointer on a write + if (data) + pkt->dataStatic(data + gen.complete()); - pkt->senderState = reqState; + // the same DMA sender state for all the request packet + // belonging to this action + pkt->senderState = reqState; - assert(pendingCount >= 0); - pendingCount++; - DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), - gen.size()); - queueDma(pkt); + DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), + gen.size()); + queueDma(pkt); } - } void -DmaHandler::queueDma(PacketPtr pkt, bool front) +DmaHandler::queueDma(PacketPtr pkt) { + transmitList.push_back(pkt); - if (front) - transmitList.push_front(pkt); - else - transmitList.push_back(pkt); + // remember that we have another packet pending + pendingCount++; + sendDma(); } @@ -228,8 +250,8 @@ 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"); + if (sendEvent.scheduled() || inRetry) { + DPRINTF(DMA, "Waiting for retry or backoff timer\n"); return; } @@ -258,52 +280,22 @@ } while (result && !backoffTime && transmitList.size()); if (transmitList.size() && backoffTime && !inRetry && - !backoffEvent.scheduled()) { + !sendEvent.scheduled()) { DPRINTF(DMA, "-- Scheduling backoff timer for %d\n", - backoffTime+curTick()); - device->schedule(backoffEvent, backoffTime + curTick()); + backoffTime + curTick()); + device->schedule(sendEvent, backoffTime + curTick()); } } else if (state == Enums::atomic) { transmitList.pop_front(); - Tick lat; - DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n", + 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(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 ); + Tick lat = sendAtomic(pkt); - 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() -{ + handleResp(pkt, lat); + } else + panic("Unknown memory command state."); } BaseMasterPort &