From 69e82539fd81299751e1000c0dac49f2eddbbdb6 Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Tue, 23 Oct 2012 04:49:33 -0400 Subject: [PATCH] dev: Remove zero-time loop in DMA timing send This patch removes the zero-time loop used to send items from the DMA port transmit list. Instead of having a loop, the DMA port now uses an event to schedule sending of a single packet. Ultimately this patch serves to ease the transition to a blocking 4-phase handshake. A follow-on patch will update the regression statistics. --- src/dev/dma_device.cc | 93 ++++++++++++++++++----------------- src/dev/dma_device.hh | 110 +++++++++++++++++++++++++----------------- 2 files changed, 116 insertions(+), 87 deletions(-) diff --git a/src/dev/dma_device.cc b/src/dev/dma_device.cc index 43d45146f..1aa4a8647 100644 --- a/src/dev/dma_device.cc +++ b/src/dev/dma_device.cc @@ -49,8 +49,8 @@ #include "sim/system.hh" DmaPort::DmaPort(MemObject *dev, System *s) - : MasterPort(dev->name() + ".dma", dev), device(dev), sys(s), - masterId(s->getMasterId(dev->name())), + : MasterPort(dev->name() + ".dma", dev), device(dev), sendEvent(this), + sys(s), masterId(s->getMasterId(dev->name())), pendingCount(0), drainEvent(NULL), inRetry(false) { } @@ -152,24 +152,7 @@ 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 (result && transmitList.size()); - - DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n", - transmitList.size(), inRetry); + trySendTimingReq(); } void @@ -198,6 +181,11 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, gen.size()); queueDma(pkt); } + + // in zero time also initiate the sending of the packets we have + // just created, for atomic this involves actually completing all + // the requests + sendDma(); } void @@ -208,8 +196,35 @@ DmaPort::queueDma(PacketPtr pkt) // remember that we have another packet pending, this will only be // decremented once a response comes back pendingCount++; +} - sendDma(); +void +DmaPort::trySendTimingReq() +{ + // send the first packet on the transmit list and schedule the + // following send if it is successful + PacketPtr pkt = transmitList.front(); + + DPRINTF(DMA, "Trying to send %s addr %#x\n", pkt->cmdString(), + pkt->getAddr()); + + inRetry = !sendTimingReq(pkt); + if (!inRetry) { + transmitList.pop_front(); + DPRINTF(DMA, "-- Done\n"); + // if there is more to do, then do so + if (!transmitList.empty()) + // this should ultimately wait for as many cycles as the + // device needs to send the packet, but currently the port + // does not have any known width so simply wait a single + // cycle + device->schedule(sendEvent, device->clockEdge(Cycles(1))); + } else { + DPRINTF(DMA, "-- Failed, waiting for retry\n"); + } + + DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n", + transmitList.size(), inRetry); } void @@ -219,37 +234,29 @@ DmaPort::sendDma() // 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 (inRetry) { - DPRINTF(DMA, "Can't send immediately, waiting for retry\n"); + // if we are either waiting for a retry or are still waiting + // after sending the last packet, then do not proceed + if (inRetry || sendEvent.scheduled()) { + DPRINTF(DMA, "Can't send immediately, waiting to send\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 && transmitList.size()); + trySendTimingReq(); } else if (state == Enums::atomic) { - transmitList.pop_front(); + // send everything there is to send in zero time + while (!transmitList.empty()) { + PacketPtr pkt = transmitList.front(); + transmitList.pop_front(); - DPRINTF(DMA, "Sending DMA for addr: %#x size: %d\n", - pkt->req->getPaddr(), pkt->req->getSize()); - Tick lat = sendAtomic(pkt); + DPRINTF(DMA, "Sending DMA for addr: %#x size: %d\n", + pkt->req->getPaddr(), pkt->req->getSize()); + Tick lat = sendAtomic(pkt); - handleResp(pkt, lat); + handleResp(pkt, lat); + } } else panic("Unknown memory mode."); } diff --git a/src/dev/dma_device.hh b/src/dev/dma_device.hh index c46fbfd76..cd328f3d6 100644 --- a/src/dev/dma_device.hh +++ b/src/dev/dma_device.hh @@ -51,49 +51,24 @@ class DmaPort : public MasterPort { - protected: - struct DmaReqState : public Packet::SenderState - { - /** Event to call on the device when this transaction (all packets) - * complete. */ - Event *completionEvent; + private: - /** Total number of bytes that this transaction involves. */ - Addr totBytes; + /** + * Take the first packet of the transmit list and attempt to send + * it as a timing request. If it is successful, schedule the + * sending of the next packet, otherwise remember that we are + * waiting for a retry. + */ + void trySendTimingReq(); - /** 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; - - /** Use a deque as we never to any insertion or removal in the middle */ - std::deque 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. */ - uint32_t pendingCount; - - /** If we need to drain, keep the drain event around until we're done - * here.*/ - Event *drainEvent; - - /** If the port is currently waiting for a retry before it can - * send whatever it is that it's sending. */ - bool inRetry; + /** + * For timing, attempt to send the first item on the transmit + * list, and if it is successful and there are more packets + * waiting, then schedule the sending of the next packet. For + * atomic, simply send and process everything on the transmit + * list. + */ + void sendDma(); /** * Handle a response packet by updating the corresponding DMA @@ -107,11 +82,59 @@ class DmaPort : public MasterPort */ void handleResp(PacketPtr pkt, Tick delay = 0); + struct DmaReqState : public Packet::SenderState + { + /** Event to call on the device when this transaction (all packets) + * complete. */ + Event *completionEvent; + + /** Total number of bytes that this transaction involves. */ + const Addr totBytes; + + /** Number of bytes that have been acked for this transaction. */ + Addr numBytes; + + /** Amount to delay completion of dma by */ + const Tick delay; + + DmaReqState(Event *ce, Addr tb, Tick _delay) + : completionEvent(ce), totBytes(tb), numBytes(0), delay(_delay) + {} + }; + + /** The device that owns this port. */ + MemObject *device; + + /** Use a deque as we never do any insertion or removal in the middle */ + std::deque transmitList; + + /** Event used to schedule a future sending from the transmit list. */ + EventWrapper sendEvent; + + /** 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 */ + const MasterID masterId; + + /** Number of outstanding packets the dma port has. */ + uint32_t pendingCount; + + /** If we need to drain, keep the drain event around until we're done + * here.*/ + Event *drainEvent; + + /** If the port is currently waiting for a retry before it can + * send whatever it is that it's sending. */ + bool inRetry; + + protected: + bool recvTimingResp(PacketPtr pkt); void recvRetry() ; void queueDma(PacketPtr pkt); - void sendDma(); public: @@ -148,7 +171,7 @@ class DmaDevice : public PioDevice dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, delay); } - bool dmaPending() { return dmaPort.dmaPending(); } + bool dmaPending() const { return dmaPort.dmaPending(); } virtual void init(); @@ -159,7 +182,6 @@ class DmaDevice : public PioDevice virtual BaseMasterPort &getMasterPort(const std::string &if_name, PortID idx = InvalidPortID); - friend class DmaPort; }; #endif // __DEV_DMA_DEVICE_HH__