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