gem5-dev@gem5.org

The gem5 Developer List

View all threads

[M] Change in gem5/gem5[develop]: dev: Add an "abortPending" method to the DMA port class.

GB
Gabe Black (Gerrit)
Sat, Apr 8, 2023 8:02 AM

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.black@gmail.com
Tested-by: kokoro noreply+kokoro@google.com
Reviewed-by: Gabe Black gabe.black@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.black@gmail.com
Gerrit-Reviewer: Gabe Black gabe.black@gmail.com
Gerrit-Reviewer: Giacomo Travaglini giacomo.travaglini@arm.com
Gerrit-Reviewer: Jui-min Lee fcrh@google.com
Gerrit-Reviewer: kokoro noreply+kokoro@google.com
Gerrit-CC: Gabe Black gabeblack@google.com
Gerrit-MessageType: merged

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.black@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Gabe Black <gabe.black@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.black@gmail.com> Gerrit-Reviewer: Gabe Black <gabe.black@gmail.com> Gerrit-Reviewer: Giacomo Travaglini <giacomo.travaglini@arm.com> Gerrit-Reviewer: Jui-min Lee <fcrh@google.com> Gerrit-Reviewer: kokoro <noreply+kokoro@google.com> Gerrit-CC: Gabe Black <gabeblack@google.com> Gerrit-MessageType: merged