Ruby: dma retry fix
authorBrad Beckmann <Brad.Beckmann@amd.com>
Sat, 19 Mar 2011 21:17:48 +0000 (14:17 -0700)
committerBrad Beckmann <Brad.Beckmann@amd.com>
Sat, 19 Mar 2011 21:17:48 +0000 (14:17 -0700)
This patch fixes the problem where Ruby would fail to call sendRetry on ports
after it nacked the port.  This patch is particularly helpful for bursty dma
requests which often include several packets.

src/mem/ruby/system/DMASequencer.cc
src/mem/ruby/system/RubyPort.cc

index fbaf5f1d14b8352806e6a809f0f6695d2ae2e5f5..e8e2790430bc9bfeaa57bc41cad581005bdec7e5 100644 (file)
@@ -116,9 +116,13 @@ DMASequencer::issueNext()
     assert(m_is_busy == true);
     active_request.bytes_completed = active_request.bytes_issued;
     if (active_request.len == active_request.bytes_completed) {
-        DPRINTF(RubyDma, "DMA request completed\n"); 
-        ruby_hit_callback(active_request.pkt);
+        //
+        // Must unset the busy flag before calling back the dma port because
+        // the callback may cause a previously nacked request to be reissued
+        //
+        DPRINTF(RubyDma, "DMA request completed\n");
         m_is_busy = false;
+        ruby_hit_callback(active_request.pkt);
         return;
     }
 
index f4bc5c95ca957f21f6ccbe020a6ea9072cba4a63..c79154566764921b785d3c4e2e9ea59d7ae3dbf7 100644 (file)
@@ -305,16 +305,26 @@ RubyPort::ruby_hit_callback(PacketPtr pkt)
     // likely has free resources now.
     //
     if (waitingOnSequencer) {
-        for (std::list<M5Port*>::iterator i = retryList.begin();
-             i != retryList.end(); ++i) {
-            (*i)->sendRetry();
-            (*i)->onRetryList(false);
-            DPRINTF(MemoryAccess,
+        //
+        // Record the current list of ports to retry on a temporary list before
+        // calling sendRetry on those ports.  sendRetry will cause an 
+        // immediate retry, which may result in the ports being put back on the
+        // list. Therefore we want to clear the retryList before calling
+        // sendRetry.
+        //
+        std::list<M5Port*> curRetryList(retryList);
+
+        retryList.clear();
+        waitingOnSequencer = false;
+        
+        for (std::list<M5Port*>::iterator i = curRetryList.begin();
+             i != curRetryList.end(); ++i) {
+            DPRINTF(RubyPort,
                     "Sequencer may now be free.  SendRetry to port %s\n",
                     (*i)->name());
+            (*i)->onRetryList(false);
+            (*i)->sendRetry();
         }
-        retryList.clear();
-        waitingOnSequencer = false;
     }
 }