summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/bridge.cc40
-rw-r--r--src/mem/bridge.hh8
-rw-r--r--src/mem/bus.cc1
-rw-r--r--src/mem/cache/cache_impl.hh25
-rw-r--r--src/mem/packet.cc6
-rw-r--r--src/mem/packet.hh6
6 files changed, 56 insertions, 30 deletions
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
index c502c5130..3434f59fb 100644
--- a/src/mem/bridge.cc
+++ b/src/mem/bridge.cc
@@ -119,17 +119,17 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n",
sendQueue.size(), queuedRequests, outstandingResponses);
- DPRINTF(BusBridge, "Remove queue size: %d outreq: %d outresp: %d\n",
+ DPRINTF(BusBridge, "Remote queue size: %d outreq: %d outresp: %d\n",
otherPort->sendQueue.size(), otherPort->queuedRequests,
otherPort->outstandingResponses);
- if (pkt->isRequest() && otherPort->reqQueueFull() && !pkt->wasNacked()) {
+ if (pkt->isRequest() && otherPort->reqQueueFull()) {
DPRINTF(BusBridge, "Remote queue full, nacking\n");
nackRequest(pkt);
return true;
}
- if (pkt->needsResponse() && !pkt->wasNacked())
+ if (pkt->needsResponse())
if (respQueueFull()) {
DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
@@ -150,8 +150,8 @@ void
Bridge::BridgePort::nackRequest(PacketPtr pkt)
{
// Nack the packet
+ pkt->makeTimingResponse();
pkt->setNacked();
- pkt->setDest(pkt->getSrc());
//put it on the list to send
Tick readyTime = curTick + nackDelay;
@@ -195,27 +195,23 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
void
Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
{
- if (pkt->isResponse() || pkt->wasNacked()) {
+ if (pkt->isResponse()) {
// This is a response for a request we forwarded earlier. The
// corresponding PacketBuffer should be stored in the packet's
// senderState field.
+
PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
assert(buf != NULL);
// set up new packet dest & senderState based on values saved
// from original request
buf->fixResponse(pkt);
- // Check if this packet was expecting a response and it's a nacked
- // packet, in which case we will never being seeing it
- if (buf->expectResponse && pkt->wasNacked())
- --outstandingResponses;
-
DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
delete buf;
}
- if (pkt->isRequest() && !pkt->wasNacked()) {
+ if (pkt->isRequest()) {
++queuedRequests;
}
@@ -249,7 +245,15 @@ Bridge::BridgePort::trySend()
buf->origSrc, pkt->getDest(), pkt->getAddr());
bool wasReq = pkt->isRequest();
- bool wasNacked = pkt->wasNacked();
+ bool was_nacked_here = buf->nackedHere;
+
+ // If the send was successful, make sure sender state was set to NULL
+ // otherwise we could get a NACK back of a packet that didn't expect a
+ // response and we would try to use freed memory.
+
+ Packet::SenderState *old_sender_state = pkt->senderState;
+ if (pkt->isRequest() && !buf->expectResponse)
+ pkt->senderState = NULL;
if (sendTiming(pkt)) {
// send successful
@@ -266,12 +270,10 @@ Bridge::BridgePort::trySend()
delete buf;
}
- if (!wasNacked) {
- if (wasReq)
- --queuedRequests;
- else
- --outstandingResponses;
- }
+ if (wasReq)
+ --queuedRequests;
+ else if (!was_nacked_here)
+ --outstandingResponses;
// If there are more packets to send, schedule event to try again.
if (!sendQueue.empty()) {
@@ -281,8 +283,10 @@ Bridge::BridgePort::trySend()
}
} else {
DPRINTF(BusBridge, " unsuccessful\n");
+ pkt->senderState = old_sender_state;
inRetry = true;
}
+
DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
sendQueue.size(), queuedRequests, outstandingResponses);
}
diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh
index 82001948e..df48eb8c5 100644
--- a/src/mem/bridge.hh
+++ b/src/mem/bridge.hh
@@ -78,17 +78,19 @@ class Bridge : public MemObject
public:
Tick ready;
PacketPtr pkt;
+ bool nackedHere;
Packet::SenderState *origSenderState;
short origSrc;
bool expectResponse;
PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
- : ready(t), pkt(_pkt),
- origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
+ : ready(t), pkt(_pkt), nackedHere(nack),
+ origSenderState(_pkt->senderState),
+ origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ),
expectResponse(_pkt->needsResponse() && !nack)
{
- if (!pkt->isResponse() && !nack && !pkt->wasNacked())
+ if (!pkt->isResponse() && !nack)
pkt->senderState = this;
}
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index 620e2ac60..3f7b1deaf 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -237,6 +237,7 @@ Bus::recvTiming(PacketPtr pkt)
if (dest_port_id == src) {
// Must be forwarded snoop up from below...
assert(dest == Packet::Broadcast);
+ assert(src != defaultId); // catch infinite loops
} else {
// send to actual target
if (!dest_port->sendTiming(pkt)) {
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index 02e951df4..f9a007c93 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -606,7 +606,13 @@ Cache<TagStore>::atomicAccess(PacketPtr pkt)
DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
busPkt->cmdString(), busPkt->getAddr(), old_state);
- if (isCacheFill) {
+ bool is_error = busPkt->isError();
+ assert(!busPkt->wasNacked());
+
+ if (is_error && pkt->needsResponse()) {
+ pkt->makeAtomicResponse();
+ pkt->copyError(busPkt);
+ } else if (isCacheFill && !is_error) {
PacketList writebacks;
blk = handleFill(busPkt, blk, writebacks);
satisfyCpuSideRequest(pkt, blk);
@@ -667,6 +673,8 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
{
Tick time = curTick + hitLatency;
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
+ bool is_error = pkt->isError();
+
assert(mshr);
if (pkt->wasNacked()) {
@@ -675,7 +683,11 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
"not implemented\n");
return;
}
- assert(!pkt->isError());
+ if (is_error) {
+ DPRINTF(Cache, "Cache received packet with error for address %x, "
+ "cmd: %s\n", pkt->getAddr(), pkt->cmdString());
+ }
+
DPRINTF(Cache, "Handling response to %x\n", pkt->getAddr());
MSHRQueue *mq = mshr->queue;
@@ -702,7 +714,7 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
miss_latency;
}
- if (mshr->isCacheFill) {
+ if (mshr->isCacheFill && !is_error) {
DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
pkt->getAddr());
@@ -744,13 +756,18 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
} else {
// not a cache fill, just forwarding response
completion_time = tags->getHitLatency() + pkt->finishTime;
- if (pkt->isRead()) {
+ if (pkt->isRead() && !is_error) {
target->pkt->setData(pkt->getPtr<uint8_t>());
}
}
target->pkt->makeTimingResponse();
+ // if this packet is an error copy that to the new packet
+ if (is_error)
+ target->pkt->copyError(pkt);
cpuSidePort->respond(target->pkt, completion_time);
} else {
+ // I don't believe that a snoop can be in an error state
+ assert(!is_error);
// response to snoop request
DPRINTF(Cache, "processing deferred snoop...\n");
handleSnoop(target->pkt, blk, true, true);
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
index c7c6ec083..7b36be599 100644
--- a/src/mem/packet.cc
+++ b/src/mem/packet.cc
@@ -117,11 +117,11 @@ MemCmd::commandInfo[] =
{ SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
InvalidCmd, "SwapResp" },
/* NetworkNackError -- nacked at network layer (not by protocol) */
- { SET2(IsRequest, IsError), InvalidCmd, "NetworkNackError" },
+ { SET2(IsResponse, IsError), InvalidCmd, "NetworkNackError" },
/* InvalidDestError -- packet dest field invalid */
- { SET2(IsRequest, IsError), InvalidCmd, "InvalidDestError" },
+ { SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" },
/* BadAddressError -- memory address invalid */
- { SET2(IsRequest, IsError), InvalidCmd, "BadAddressError" }
+ { SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" }
};
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index 2b650a51e..9c366f9fc 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -332,10 +332,11 @@ class Packet : public FastAlloc
// Network error conditions... encapsulate them as methods since
// their encoding keeps changing (from result field to command
// field, etc.)
- void setNacked() { origCmd = cmd; cmd = MemCmd::NetworkNackError; }
- void setBadAddress() { origCmd = cmd; cmd = MemCmd::BadAddressError; }
+ void setNacked() { assert(isResponse()); cmd = MemCmd::NetworkNackError; }
+ void setBadAddress() { assert(isResponse()); cmd = MemCmd::BadAddressError; }
bool wasNacked() { return cmd == MemCmd::NetworkNackError; }
bool hadBadAddress() { return cmd == MemCmd::BadAddressError; }
+ void copyError(Packet *pkt) { assert(pkt->isError()); cmd = pkt->cmd; }
bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
@@ -431,6 +432,7 @@ class Packet : public FastAlloc
{
assert(needsResponse());
assert(isRequest());
+ origCmd = cmd;
cmd = cmd.responseCommand();
dest = src;
destValid = srcValid;