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>
This commit is contained in:
Gabe Black
2023-03-29 02:31:13 -07:00
committed by Gabe Black
parent c98d0d2f93
commit 2f5c87c7c6
2 changed files with 86 additions and 17 deletions

View File

@@ -81,6 +81,8 @@ DmaPort::handleRespPacket(PacketPtr pkt, Tick delay)
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 @@ DmaPort::handleResp(DmaReqState *state, Addr addr, Addr size, Tick delay)
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 @@ DmaPort::drain()
void
DmaPort::recvReqRetry()
{
assert(transmitList.size());
trySendTimingReq();
retryPending = false;
if (transmitList.size())
trySendTimingReq();
}
void
@@ -184,7 +198,6 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
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
@@ -200,6 +213,42 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
defaultSid, defaultSSid, delay, flag);
}
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()
{
@@ -216,14 +265,17 @@ DmaPort::trySendTimingReq()
// 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 @@ DmaPort::trySendTimingReq()
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 @@ DmaPort::sendAtomicReq(DmaReqState *state)
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 @@ bool
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 @@ DmaPort::sendDma()
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;
}

View File

@@ -85,6 +85,12 @@ class DmaPort : public RequestPort, public Drainable
* 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 @@ class DmaPort : public RequestPort, public Drainable
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 @@ class DmaPort : public RequestPort, public Drainable
/** 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 @@ class DmaPort : public RequestPort, public Drainable
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;