changeset 98e05d58f9eb in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=98e05d58f9eb
description:
        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.

diffstat:

 src/dev/dma_device.cc |   95 +++++++++++++++++++++++--------------------
 src/dev/dma_device.hh |  110 ++++++++++++++++++++++++++++++--------------------
 2 files changed, 117 insertions(+), 88 deletions(-)

diffs (289 lines):

diff -r d6bca167cee4 -r 98e05d58f9eb src/dev/dma_device.cc
--- a/src/dev/dma_device.cc     Tue Oct 23 04:24:32 2012 -0400
+++ b/src/dev/dma_device.cc     Tue Oct 23 04:49:33 2012 -0400
@@ -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 @@
 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 @@
                 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 @@
     // 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 @@
     // 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());
+        trySendTimingReq();
+    } else if (state == Enums::atomic) {
+        // send everything there is to send in zero time
+        while (!transmitList.empty()) {
+            PacketPtr pkt = transmitList.front();
+            transmitList.pop_front();
 
-        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());
-    } else if (state == Enums::atomic) {
-        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 -r d6bca167cee4 -r 98e05d58f9eb src/dev/dma_device.hh
--- a/src/dev/dma_device.hh     Tue Oct 23 04:24:32 2012 -0400
+++ b/src/dev/dma_device.hh     Tue Oct 23 04:49:33 2012 -0400
@@ -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<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. */
-    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 @@
      */
     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<PacketPtr> transmitList;
+
+    /** Event used to schedule a future sending from the transmit list. */
+    EventWrapper<DmaPort, &DmaPort::sendDma> 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 @@
         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 @@
     virtual BaseMasterPort &getMasterPort(const std::string &if_name,
                                           PortID idx = InvalidPortID);
 
-    friend class DmaPort;
 };
 
 #endif // __DEV_DMA_DEVICE_HH__
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to