Gabe Black has submitted this change. ( https://gem5-review.googlesource.com/c/public/gem5/+/69437?usp=email )

Change subject: dev: Add an "abortPending" method to the DMA port class.
......................................................................

dev: Add an "abortPending" method to the DMA port class.

This will abort any pending transactions that have been given to the
port.

Change-Id: Ie5f2c702530656a0c4590461369d430abead14cd
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/69437
Maintainer: Gabe Black <gabe.bl...@gmail.com>
Tested-by: kokoro <noreply+kok...@google.com>
Reviewed-by: Gabe Black <gabe.bl...@gmail.com>
---
M src/dev/dma_device.cc
M src/dev/dma_device.hh
2 files changed, 86 insertions(+), 17 deletions(-)

Approvals:
  Gabe Black: Looks good to me, approved; Looks good to me, approved
  kokoro: Regressions pass




diff --git a/src/dev/dma_device.cc b/src/dev/dma_device.cc
index ebda635..24e931e 100644
--- a/src/dev/dma_device.cc
+++ b/src/dev/dma_device.cc
@@ -81,6 +81,8 @@
 void
 DmaPort::handleResp(DmaReqState *state, Addr addr, Addr size, Tick delay)
 {
+    assert(pendingCount != 0);
+    pendingCount--;
     DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d,"  \
             " tot: %d sched %d\n",
             MemCmd(state->cmd).toString(), addr, size,
@@ -93,11 +95,22 @@
     state->numBytes += size;
     assert(state->totBytes >= state->numBytes);

-    // If we have reached the total number of bytes for this DMA request,
-    // then signal the completion and delete the sate.
-    if (state->totBytes == state->numBytes) {
-        assert(pendingCount != 0);
-        pendingCount--;
+    bool all_bytes = (state->totBytes == state->numBytes);
+    if (state->aborted) {
+ // If this request was aborted, check to see if its in flight accesses
+        // have finished. There may be packets for more than one request in
+        // flight at a time, so check for finished requests, or no more
+        // packets.
+        if (all_bytes || pendingCount == 0) {
+ // If yes, signal its abort event (if any) and delete the state.
+            if (state->abortEvent) {
+                device->schedule(state->abortEvent, curTick());
+            }
+            delete state;
+        }
+    } else if (all_bytes) {
+        // If we have reached the end of this DMA request, then signal the
+        // completion and delete the sate.
         if (state->completionEvent) {
             delay += state->delay;
             device->schedule(state->completionEvent, curTick() + delay);
@@ -166,8 +179,9 @@
 void
 DmaPort::recvReqRetry()
 {
-    assert(transmitList.size());
-    trySendTimingReq();
+    retryPending = false;
+    if (transmitList.size())
+        trySendTimingReq();
 }

 void
@@ -184,7 +198,6 @@
     transmitList.push_back(
             new DmaReqState(cmd, addr, cacheLineSize, size,
                 data, flag, requestorId, sid, ssid, event, delay));
-    pendingCount++;

// In zero time, also initiate the sending of the packets for the request // we have just created. For atomic this involves actually completing all
@@ -201,6 +214,42 @@
 }

 void
+DmaPort::abortPending()
+{
+    if (inRetry) {
+        delete inRetry;
+        inRetry = nullptr;
+    }
+
+    if (pendingCount && !transmitList.empty()) {
+        auto *state = transmitList.front();
+        if (state->numBytes != state->gen.complete()) {
+ // In flight packets refer to the transmission at the front of the + // list, and not a transmission whose packets have all been sent + // but not completed. Preserve the state so the packets don't have
+            // dangling pointers.
+            transmitList.pop_front();
+            state->aborted = true;
+        }
+    }
+
+    // Get rid of requests that haven't started yet.
+    while (!transmitList.empty()) {
+        auto *state = transmitList.front();
+        if (state->abortEvent)
+            device->schedule(state->abortEvent, curTick());
+        delete state;
+        transmitList.pop_front();
+    }
+
+    if (sendEvent.scheduled())
+        device->deschedule(sendEvent);
+
+    if (pendingCount == 0)
+        signalDrainDone();
+}
+
+void
 DmaPort::trySendTimingReq()
 {
     // Send the next packet for the first DMA request on the transmit list,
@@ -216,14 +265,17 @@
// Check if this was the last packet now, since hypothetically the packet
     // response may come immediately, and state may be deleted.
     bool last = state->gen.last();
-    if (!sendTimingReq(pkt))
+    if (sendTimingReq(pkt)) {
+        pendingCount++;
+    } else {
+        retryPending = true;
         inRetry = pkt;
-    if (!inRetry) {
+    }
+    if (!retryPending) {
+        state->gen.next();
// If that was the last packet from this request, pop it from the list.
         if (last)
             transmitList.pop_front();
-        else
-            state->gen.next();
         DPRINTF(DMA, "-- Done\n");
         // If there is more to do, then do so.
         if (!transmitList.empty()) {
@@ -236,8 +288,8 @@
         DPRINTF(DMA, "-- Failed, waiting for retry\n");
     }

-    DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n",
-            transmitList.size(), inRetry ? 1 : 0);
+    DPRINTF(DMA, "TransmitList: %d, retryPending: %d\n",
+            transmitList.size(), retryPending ? 1 : 0);
 }

 bool
@@ -246,6 +298,7 @@
     PacketPtr pkt = state->createPacket();
     DPRINTF(DMA, "Sending  DMA for addr: %#x size: %d\n",
             state->gen.addr(), state->gen.size());
+    pendingCount++;
     Tick lat = sendAtomic(pkt);

     // Check if we're done, since handleResp may delete state.
@@ -258,6 +311,7 @@
 DmaPort::sendAtomicBdReq(DmaReqState *state)
 {
     bool done = false;
+    pendingCount++;

     auto bd_it = memBackdoors.contains(state->gen.addr());
     if (bd_it == memBackdoors.end()) {
@@ -336,7 +390,7 @@
     if (sys->isTimingMode()) {
         // 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()) {
+        if (retryPending || sendEvent.scheduled()) {
             DPRINTF(DMA, "Can't send immediately, waiting to send\n");
             return;
         }
diff --git a/src/dev/dma_device.hh b/src/dev/dma_device.hh
index 2a3468c..92b44bf 100644
--- a/src/dev/dma_device.hh
+++ b/src/dev/dma_device.hh
@@ -85,6 +85,12 @@
          * complete. */
         Event *completionEvent;

+ /** Event to call on the device when this transaction is aborted. */
+        Event *abortEvent;
+
+        /** Whether this request was aborted. */
+        bool aborted = false;
+
         /** Total number of bytes that this transaction involves. */
         const Addr totBytes;

@@ -115,8 +121,9 @@

DmaReqState(Packet::Command _cmd, Addr addr, Addr chunk_sz, Addr tb,
                     uint8_t *_data, Request::Flags _flags, RequestorID _id,
-                    uint32_t _sid, uint32_t _ssid, Event *ce, Tick _delay)
-            : completionEvent(ce), totBytes(tb), delay(_delay),
+                    uint32_t _sid, uint32_t _ssid, Event *ce, Tick _delay,
+                    Event *ae=nullptr)
+ : completionEvent(ce), abortEvent(ae), totBytes(tb), delay(_delay),
               gen(addr, tb, chunk_sz), data(_data), flags(_flags), id(_id),
               sid(_sid), ssid(_ssid), cmd(_cmd)
         {}
@@ -168,6 +175,11 @@

     /** The packet (if any) waiting for a retry to send. */
     PacketPtr inRetry = nullptr;
+    /**
+     * Whether the other side expects us to wait for a retry. We may have
+ * decided not to actually send the packet by the time we get the retry.
+     */
+    bool retryPending = false;

     /** Default streamId */
     const uint32_t defaultSid;
@@ -195,6 +207,9 @@
               uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay,
               Request::Flags flag=0);

+    // Abort and remove any pending DMA transmissions.
+    void abortPending();
+
     bool dmaPending() const { return pendingCount > 0; }

     DrainState drain() override;

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/69437?usp=email To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Ie5f2c702530656a0c4590461369d430abead14cd
Gerrit-Change-Number: 69437
Gerrit-PatchSet: 3
Gerrit-Owner: Gabe Black <gabe.bl...@gmail.com>
Gerrit-Reviewer: Gabe Black <gabe.bl...@gmail.com>
Gerrit-Reviewer: Giacomo Travaglini <giacomo.travagl...@arm.com>
Gerrit-Reviewer: Jui-min Lee <f...@google.com>
Gerrit-Reviewer: kokoro <noreply+kok...@google.com>
Gerrit-CC: Gabe Black <gabebl...@google.com>
Gerrit-MessageType: merged
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org

Reply via email to