mem: Introduce a variable for the retrying port
authorAndreas Hansson <andreas.hansson@arm.com>
Tue, 26 Mar 2013 18:46:46 +0000 (14:46 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Tue, 26 Mar 2013 18:46:46 +0000 (14:46 -0400)
This patch introduces a variable to keep track of the retrying port
instead of relying on it being the front of the retryList.

Besides the improvement in readability, this patch is a step towards
separating out the two cases where a port is waiting for the bus to be
free, and where the forwarding did not succeed and the bus is waiting
for a retry to pass on to the original initiator of the transaction.

The changes made are currently such that the regressions are not
affected. This is ensured by always prioritizing the currently
retrying port and putting it back at the front of the retry list.

src/mem/bus.cc
src/mem/bus.hh

index d29422593214fd3971b8a5c6410988c1afa0a459..88b91983b2ae610b71877e57fd804f16fe3871ec 100644 (file)
@@ -160,7 +160,7 @@ template <typename PortClass>
 BaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name) :
     Drainable(),
     bus(_bus), _name(_name), state(IDLE), drainManager(NULL),
-    releaseEvent(this)
+    retryingPort(NULL), releaseEvent(this)
 {
 }
 
@@ -192,12 +192,17 @@ BaseBus::Layer<PortClass>::tryTiming(PortClass* port)
 {
     // first we see if the bus is busy, next we check if we are in a
     // retry with a port other than the current one
-    if (state == BUSY || (state == RETRY && port != retryList.front())) {
+    if (state == BUSY || (state == RETRY && port != retryingPort)) {
         // put the port at the end of the retry list
         retryList.push_back(port);
         return false;
     }
 
+    // @todo: here we should no longer consider this port retrying
+    // once we can differentiate retries due to a busy bus and a
+    // failed forwarding, for now keep it so we can stick it back at
+    // the front of the retry list if needed
+
     // update the state which is shared for request, response and
     // snoop responses, if we were idle we are now busy, if we are in
     // a retry, then do not change
@@ -211,12 +216,13 @@ template <typename PortClass>
 void
 BaseBus::Layer<PortClass>::succeededTiming(Tick busy_time)
 {
-    // if a retrying port succeeded, also take it off the retry list
+    // if a retrying port succeeded, update the state and reset the
+    // retrying port
     if (state == RETRY) {
-        DPRINTF(BaseBus, "Remove retry from list %s\n",
-                retryList.front()->name());
-        retryList.pop_front();
+        DPRINTF(BaseBus, "Succeeded retry from %s\n",
+                retryingPort->name());
         state = BUSY;
+        retryingPort = NULL;
     }
 
     // we should either have gone from idle to busy in the
@@ -231,10 +237,17 @@ template <typename PortClass>
 void
 BaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time)
 {
-    // if we are not in a retry, i.e. busy (but never idle), or we are
-    // in a retry but not for the current port, then add the port at
-    // the end of the retry list
-    if (state != RETRY || port != retryList.front()) {
+    // if the current failing port is the retrying one, then for now stick it
+    // back at the front of the retry list to not change any regressions
+    if (state == RETRY) {
+        // we should never see a retry from any port but the current
+        // retry port at this point
+        assert(port == retryingPort);
+        retryList.push_front(port);
+        retryingPort = NULL;
+    } else {
+        // if we are not in a retry, i.e. busy (but never idle), then
+        // add the port at the end of the retry list
         retryList.push_back(port);
     }
 
@@ -283,25 +296,28 @@ BaseBus::Layer<PortClass>::retryWaiting()
     // we always go to retrying from idle
     assert(state == IDLE);
 
-    // update the state which is shared for request, response and
-    // snoop responses
+    // update the state
     state = RETRY;
 
+    // set the retrying port to the front of the retry list and pop it
+    // off the list
+    assert(retryingPort == NULL);
+    retryingPort = retryList.front();
+    retryList.pop_front();
+
     // note that we might have blocked on the receiving port being
     // busy (rather than the bus itself) and now call retry before the
     // destination called retry on the bus
-    retryList.front()->sendRetry();
+    retryingPort->sendRetry();
 
     // If the bus is still in the retry state, sendTiming wasn't
     // called in zero time (e.g. the cache does this)
     if (state == RETRY) {
-        retryList.pop_front();
-
         //Burn a cycle for the missed grant.
 
-        // update the state which is shared for request, response and
-        // snoop responses
+        // update the state to busy and reset the retrying port
         state = BUSY;
+        retryingPort = NULL;
 
         // occupy the bus layer until the next cycle ends
         occupyLayer(bus.clockEdge(Cycles(1)));
index 705a3a999cd2a9d6df943b49cd8abd717a4db14d..2cd21ff85a640c3c6bbfdbe0e3fecd3fde2604ea 100644 (file)
@@ -211,6 +211,14 @@ class BaseBus : public MemObject
          */
         std::deque<PortClass*> retryList;
 
+        /**
+         * Port that we are currently in the process of telling to
+         * retry a previously failed attempt to perform a timing
+         * transaction. This is a valid port when in the retry state,
+         * and NULL when in busy or idle.
+         */
+        PortClass* retryingPort;
+
         /**
          * Release the bus layer after being occupied and return to an
          * idle state where we proceed to send a retry to any