mem: Make returning snoop responses occupy response layer
authorAndreas Hansson <andreas.hansson@arm.com>
Thu, 30 May 2013 16:54:02 +0000 (12:54 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Thu, 30 May 2013 16:54:02 +0000 (12:54 -0400)
This patch introduces a mirrored internal snoop port to facilitate
easy addition of flow control for the snoop responses that are turned
into normal responses on their return. To perform this, the slave
ports of the coherent bus are wrapped in internal master ports that
are passed as the source ports to the response layer in question.

As a result of this patch, there is more contention for the response
resources, and as such system performance will decrease slightly.

A consequence of the mirrored internal port is that the port the bus
tells to retry (the internal one) and the port actually retrying (the
mirrored) one are not the same. Thus, the existing check in tryTiming
is not longer correct. In fact, the test is redundant as the layer is
only in the retry state while calling sendRetry on the waiting port,
and if the latter does not immediately call the bus then the retry
state is left. Consequently the check is removed.

src/mem/bus.cc
src/mem/coherent_bus.cc
src/mem/coherent_bus.hh
src/mem/port.hh

index 855f82db4989d1f6eb75c7d073d7abc8fd784ba0..d94bd6a28b692e5526da7e57210e1e54cf98403c 100644 (file)
@@ -189,12 +189,20 @@ template <typename SrcType, typename DstType>
 bool
 BaseBus::Layer<SrcType,DstType>::tryTiming(SrcType* src_port)
 {
-    // first we see if the layer is busy, next we check if we are in a
-    // retry with a port other than the current one, lastly we check
-    // if the destination port is already engaged in a transaction
-    // waiting for a retry from the peer
-    if (state == BUSY || (state == RETRY && src_port != retryingPort) ||
-        waitingForPeer != NULL) {
+    // if we are in the retry state, we will not see anything but the
+    // retrying port (or in the case of the snoop ports the snoop
+    // response port that mirrors the actual slave port) as we leave
+    // this state again in zero time if the peer does not immediately
+    // call the bus when receiving the retry
+
+    // first we see if the layer is busy, next we check if the
+    // destination port is already engaged in a transaction waiting
+    // for a retry from the peer
+    if (state == BUSY || waitingForPeer != NULL) {
+        // the port should not be waiting already
+        assert(std::find(waitingForLayer.begin(), waitingForLayer.end(),
+                         src_port) == waitingForLayer.end());
+
         // put the port at the end of the retry list waiting for the
         // layer to be freed up (and in the case of a busy peer, for
         // that transaction to go through, and then the bus to free
index 20597bc3ae2445cf4112603acfa6536abc0ca523..756d4c05c30e30402ee91c3f80feae8b30537d44 100644 (file)
@@ -92,6 +92,7 @@ CoherentBus::CoherentBus(const CoherentBusParams *p)
         slavePorts.push_back(bp);
         respLayers.push_back(new RespLayer(*bp, *this,
                                            csprintf(".respLayer%d", i)));
+        snoopRespPorts.push_back(new SnoopRespPort(*bp, *this));
     }
 
     clearPortCache();
@@ -105,6 +106,8 @@ CoherentBus::~CoherentBus()
         delete *l;
     for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l)
         delete *l;
+    for (auto p = snoopRespPorts.begin(); p != snoopRespPorts.end(); ++p)
+        delete *p;
 }
 
 void
@@ -338,6 +341,14 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
                     src_port->name(), pkt->cmdString(), pkt->getAddr());
             return false;
         }
+    } else {
+        // get the master port that mirrors this slave port internally
+        MasterPort* snoop_port = snoopRespPorts[slave_port_id];
+        if (!respLayers[dest_port_id]->tryTiming(snoop_port)) {
+            DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
+                    snoop_port->name(), pkt->cmdString(), pkt->getAddr());
+            return false;
+        }
     }
 
     DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x\n",
@@ -393,6 +404,8 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
         // currently it is illegal to block responses... can lead
         // to deadlock
         assert(success);
+
+        respLayers[dest_port_id]->succeededTiming(packetFinishTime);
     }
 
     // stats updates
index d8ddd507c764b084f25e8d3b08861d634655a9c0..49f7ae6984d9e22516220a306d078125de2259e2 100644 (file)
@@ -219,6 +219,57 @@ class CoherentBus : public BaseBus
 
     };
 
+    /**
+     * Internal class to bridge between an incoming snoop response
+     * from a slave port and forwarding it through an outgoing slave
+     * port. It is effectively a dangling master port.
+     */
+    class SnoopRespPort : public MasterPort
+    {
+
+      private:
+
+        /** The port which we mirror internally. */
+        SlavePort& slavePort;
+
+        /** The bus to which this port belongs. */
+        CoherentBus &bus;
+
+      public:
+
+        /**
+         * Create a snoop response port that mirrors a given slave port.
+         */
+        SnoopRespPort(SlavePort& slave_port, CoherentBus& _bus) :
+            MasterPort(slave_port.name() + ".snoopRespPort", &_bus),
+            slavePort(slave_port), bus(_bus) { }
+
+        /**
+         * Override the sending of retries and pass them on through
+         * the mirrored slave port.
+         */
+        void sendRetry() {
+            slavePort.sendRetry();
+        }
+
+        /**
+         * Provided as necessary.
+         */
+        void recvRetry() { panic("SnoopRespPort should never see retry\n"); }
+
+        /**
+         * Provided as necessary.
+         */
+        bool recvTimingResp(PacketPtr pkt)
+        {
+            panic("SnoopRespPort should never see timing response\n");
+            return false;
+        }
+
+    };
+
+    std::vector<SnoopRespPort*> snoopRespPorts;
+
     std::vector<SlavePort*> snoopPorts;
 
     /**
index a4e823796e5d5fd6b5aa0d532216a2757aa4f040..18db800b680f57260e51657b8b3d03d592964c82 100644 (file)
@@ -251,7 +251,7 @@ class MasterPort : public BaseMasterPort
      * Send a retry to the slave port that previously attempted a
      * sendTimingResp to this master port and failed.
      */
-    void sendRetry();
+    virtual void sendRetry();
 
     /**
      * Determine if this master port is snooping or not. The default